зеркало из https://github.com/mozilla/gecko-dev.git
Merge mozilla-central to autoland. on a CLOSED TREE
This commit is contained in:
Коммит
6043805daf
|
@ -1241,9 +1241,10 @@ pref("services.sync.syncedTabs.showRemoteIcons", true);
|
||||||
|
|
||||||
// Developer edition preferences
|
// Developer edition preferences
|
||||||
#ifdef MOZ_DEV_EDITION
|
#ifdef MOZ_DEV_EDITION
|
||||||
sticky_pref("lightweightThemes.selectedThemeID", "firefox-compact-dark@mozilla.org");
|
pref("lightweightThemes.selectedThemeID", "firefox-compact-dark@mozilla.org",
|
||||||
|
sticky);
|
||||||
#else
|
#else
|
||||||
sticky_pref("lightweightThemes.selectedThemeID", "");
|
pref("lightweightThemes.selectedThemeID", "", sticky);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Whether the character encoding menu is under the main Firefox button. This
|
// Whether the character encoding menu is under the main Firefox button. This
|
||||||
|
|
|
@ -13,9 +13,9 @@ pref("devtools.jsonview.enabled", true);
|
||||||
|
|
||||||
// Default theme ("dark" or "light")
|
// Default theme ("dark" or "light")
|
||||||
#ifdef MOZ_DEV_EDITION
|
#ifdef MOZ_DEV_EDITION
|
||||||
sticky_pref("devtools.theme", "dark");
|
pref("devtools.theme", "dark", sticky);
|
||||||
#else
|
#else
|
||||||
sticky_pref("devtools.theme", "light");
|
pref("devtools.theme", "light", sticky);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Should the devtools toolbar be opened on startup
|
// Should the devtools toolbar be opened on startup
|
||||||
|
@ -38,4 +38,4 @@ pref("devtools.onboarding.telemetry.logged", false);
|
||||||
|
|
||||||
// Completely disable DevTools entry points, as well as all DevTools command line
|
// Completely disable DevTools entry points, as well as all DevTools command line
|
||||||
// arguments This should be merged with devtools.enabled, see Bug 1440675.
|
// arguments This should be merged with devtools.enabled, see Bug 1440675.
|
||||||
pref("devtools.policy.disabled", false);
|
pref("devtools.policy.disabled", false);
|
||||||
|
|
|
@ -76,7 +76,6 @@ static HWND sWinlessPopupSurrogateHWND = nullptr;
|
||||||
static User32TrackPopupMenu sUser32TrackPopupMenuStub = nullptr;
|
static User32TrackPopupMenu sUser32TrackPopupMenuStub = nullptr;
|
||||||
|
|
||||||
typedef HIMC (WINAPI *Imm32ImmGetContext)(HWND hWND);
|
typedef HIMC (WINAPI *Imm32ImmGetContext)(HWND hWND);
|
||||||
typedef BOOL (WINAPI *Imm32ImmReleaseContext)(HWND hWND, HIMC hIMC);
|
|
||||||
typedef LONG (WINAPI *Imm32ImmGetCompositionString)(HIMC hIMC,
|
typedef LONG (WINAPI *Imm32ImmGetCompositionString)(HIMC hIMC,
|
||||||
DWORD dwIndex,
|
DWORD dwIndex,
|
||||||
LPVOID lpBuf,
|
LPVOID lpBuf,
|
||||||
|
@ -87,7 +86,6 @@ typedef BOOL (WINAPI *Imm32ImmNotifyIME)(HIMC hIMC, DWORD dwAction,
|
||||||
DWORD dwIndex, DWORD dwValue);
|
DWORD dwIndex, DWORD dwValue);
|
||||||
static WindowsDllInterceptor sImm32Intercept;
|
static WindowsDllInterceptor sImm32Intercept;
|
||||||
static Imm32ImmGetContext sImm32ImmGetContextStub = nullptr;
|
static Imm32ImmGetContext sImm32ImmGetContextStub = nullptr;
|
||||||
static Imm32ImmReleaseContext sImm32ImmReleaseContextStub = nullptr;
|
|
||||||
static Imm32ImmGetCompositionString sImm32ImmGetCompositionStringStub = nullptr;
|
static Imm32ImmGetCompositionString sImm32ImmGetCompositionStringStub = nullptr;
|
||||||
static Imm32ImmSetCandidateWindow sImm32ImmSetCandidateWindowStub = nullptr;
|
static Imm32ImmSetCandidateWindow sImm32ImmSetCandidateWindowStub = nullptr;
|
||||||
static Imm32ImmNotifyIME sImm32ImmNotifyIME = nullptr;
|
static Imm32ImmNotifyIME sImm32ImmNotifyIME = nullptr;
|
||||||
|
@ -2035,17 +2033,6 @@ PluginInstanceChild::ImmGetContextProc(HWND aWND)
|
||||||
return sHookIMC;
|
return sHookIMC;
|
||||||
}
|
}
|
||||||
|
|
||||||
// static
|
|
||||||
BOOL
|
|
||||||
PluginInstanceChild::ImmReleaseContextProc(HWND aWND, HIMC aIMC)
|
|
||||||
{
|
|
||||||
if (aIMC == sHookIMC) {
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
return sImm32ImmReleaseContextStub(aWND, aIMC);
|
|
||||||
}
|
|
||||||
|
|
||||||
// static
|
// static
|
||||||
LONG
|
LONG
|
||||||
PluginInstanceChild::ImmGetCompositionStringProc(HIMC aIMC, DWORD aIndex,
|
PluginInstanceChild::ImmGetCompositionStringProc(HIMC aIMC, DWORD aIndex,
|
||||||
|
@ -2130,16 +2117,15 @@ PluginInstanceChild::InitImm32Hook()
|
||||||
}
|
}
|
||||||
|
|
||||||
// When using windowless plugin, IMM API won't work due ot OOP.
|
// When using windowless plugin, IMM API won't work due ot OOP.
|
||||||
|
//
|
||||||
|
// ImmReleaseContext on Windows 7+ just returns TRUE only, so we don't
|
||||||
|
// need to hook this.
|
||||||
|
|
||||||
sImm32Intercept.Init("imm32.dll");
|
sImm32Intercept.Init("imm32.dll");
|
||||||
sImm32Intercept.AddHook(
|
sImm32Intercept.AddHook(
|
||||||
"ImmGetContext",
|
"ImmGetContext",
|
||||||
reinterpret_cast<intptr_t>(ImmGetContextProc),
|
reinterpret_cast<intptr_t>(ImmGetContextProc),
|
||||||
(void**)&sImm32ImmGetContextStub);
|
(void**)&sImm32ImmGetContextStub);
|
||||||
sImm32Intercept.AddHook(
|
|
||||||
"ImmReleaseContext",
|
|
||||||
reinterpret_cast<intptr_t>(ImmReleaseContextProc),
|
|
||||||
(void**)&sImm32ImmReleaseContextStub);
|
|
||||||
sImm32Intercept.AddHook(
|
sImm32Intercept.AddHook(
|
||||||
"ImmGetCompositionStringW",
|
"ImmGetCompositionStringW",
|
||||||
reinterpret_cast<intptr_t>(ImmGetCompositionStringProc),
|
reinterpret_cast<intptr_t>(ImmGetCompositionStringProc),
|
||||||
|
|
|
@ -335,7 +335,6 @@ private:
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static HIMC WINAPI ImmGetContextProc(HWND aWND);
|
static HIMC WINAPI ImmGetContextProc(HWND aWND);
|
||||||
static BOOL WINAPI ImmReleaseContextProc(HWND aWND, HIMC aIMC);
|
|
||||||
static LONG WINAPI ImmGetCompositionStringProc(HIMC aIMC, DWORD aIndex,
|
static LONG WINAPI ImmGetCompositionStringProc(HIMC aIMC, DWORD aIndex,
|
||||||
LPVOID aBuf, DWORD aLen);
|
LPVOID aBuf, DWORD aLen);
|
||||||
static BOOL WINAPI ImmSetCandidateWindowProc(HIMC hIMC,
|
static BOOL WINAPI ImmSetCandidateWindowProc(HIMC hIMC,
|
||||||
|
|
|
@ -136,12 +136,25 @@ using mozilla::TimeStamp;
|
||||||
|
|
||||||
// Avoid an unnecessary NSPR dependency on Linux and OS X just for the shell.
|
// Avoid an unnecessary NSPR dependency on Linux and OS X just for the shell.
|
||||||
#ifdef JS_POSIX_NSPR
|
#ifdef JS_POSIX_NSPR
|
||||||
|
|
||||||
|
enum PRLibSpecType { PR_LibSpec_Pathname };
|
||||||
|
|
||||||
|
struct PRLibSpec {
|
||||||
|
PRLibSpecType type;
|
||||||
|
union {
|
||||||
|
const char *pathname;
|
||||||
|
} value;
|
||||||
|
};
|
||||||
|
|
||||||
typedef void PRLibrary;
|
typedef void PRLibrary;
|
||||||
|
|
||||||
static PRLibrary*
|
#define PR_LD_NOW RTLD_NOW
|
||||||
PR_LoadLibrary(const char* path)
|
#define PR_LD_GLOBAL RTLD_GLOBAL
|
||||||
|
|
||||||
|
static PRLibrary *
|
||||||
|
PR_LoadLibraryWithFlags(PRLibSpec libSpec, int flags)
|
||||||
{
|
{
|
||||||
return dlopen(path, RTLD_LAZY | RTLD_GLOBAL);
|
return dlopen(libSpec.value.pathname, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
|
|
@ -596,8 +596,9 @@ public:
|
||||||
|
|
||||||
nsresult SetDefaultValue(PrefType aType,
|
nsresult SetDefaultValue(PrefType aType,
|
||||||
PrefValue aValue,
|
PrefValue aValue,
|
||||||
bool aFromFile,
|
|
||||||
bool aIsSticky,
|
bool aIsSticky,
|
||||||
|
bool aIsLocked,
|
||||||
|
bool aFromFile,
|
||||||
bool* aValueChanged)
|
bool* aValueChanged)
|
||||||
{
|
{
|
||||||
// Types must always match when setting the default value.
|
// Types must always match when setting the default value.
|
||||||
|
@ -607,20 +608,25 @@ public:
|
||||||
|
|
||||||
// Should we set the default value? Only if the pref is not locked, and
|
// Should we set the default value? Only if the pref is not locked, and
|
||||||
// doing so would change the default value.
|
// doing so would change the default value.
|
||||||
if (!IsLocked() && !ValueMatches(PrefValueKind::Default, aType, aValue)) {
|
if (!IsLocked()) {
|
||||||
mDefaultValue.Replace(Type(), aType, aValue);
|
if (aIsLocked) {
|
||||||
mHasDefaultValue = true;
|
SetIsLocked(true);
|
||||||
if (!aFromFile) {
|
|
||||||
mHasChangedSinceInit = true;
|
|
||||||
}
|
}
|
||||||
if (aIsSticky) {
|
if (!ValueMatches(PrefValueKind::Default, aType, aValue)) {
|
||||||
mIsSticky = true;
|
mDefaultValue.Replace(Type(), aType, aValue);
|
||||||
|
mHasDefaultValue = true;
|
||||||
|
if (!aFromFile) {
|
||||||
|
mHasChangedSinceInit = true;
|
||||||
|
}
|
||||||
|
if (aIsSticky) {
|
||||||
|
mIsSticky = true;
|
||||||
|
}
|
||||||
|
if (!mHasUserValue) {
|
||||||
|
*aValueChanged = true;
|
||||||
|
}
|
||||||
|
// What if we change the default to be the same as the user value?
|
||||||
|
// Should we clear the user value? Currently we don't.
|
||||||
}
|
}
|
||||||
if (!mHasUserValue) {
|
|
||||||
*aValueChanged = true;
|
|
||||||
}
|
|
||||||
// What if we change the default to be the same as the user value?
|
|
||||||
// Should we clear the user value? Currently we don't.
|
|
||||||
}
|
}
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
@ -820,8 +826,6 @@ static PLDHashTable* gHashTable;
|
||||||
static CallbackNode* gFirstCallback = nullptr;
|
static CallbackNode* gFirstCallback = nullptr;
|
||||||
static CallbackNode* gLastPriorityNode = nullptr;
|
static CallbackNode* gLastPriorityNode = nullptr;
|
||||||
|
|
||||||
static bool gIsAnyPrefLocked = false;
|
|
||||||
|
|
||||||
// These are only used during the call to NotifyCallbacks().
|
// These are only used during the call to NotifyCallbacks().
|
||||||
static bool gCallbacksInProgress = false;
|
static bool gCallbacksInProgress = false;
|
||||||
static bool gShouldCleanupDeadNodes = false;
|
static bool gShouldCleanupDeadNodes = false;
|
||||||
|
@ -946,6 +950,7 @@ pref_SetPref(const char* aPrefName,
|
||||||
PrefValueKind aKind,
|
PrefValueKind aKind,
|
||||||
PrefValue aValue,
|
PrefValue aValue,
|
||||||
bool aIsSticky,
|
bool aIsSticky,
|
||||||
|
bool aIsLocked,
|
||||||
bool aFromFile)
|
bool aFromFile)
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(NS_IsMainThread());
|
MOZ_ASSERT(NS_IsMainThread());
|
||||||
|
@ -968,9 +973,10 @@ pref_SetPref(const char* aPrefName,
|
||||||
bool valueChanged = false;
|
bool valueChanged = false;
|
||||||
nsresult rv;
|
nsresult rv;
|
||||||
if (aKind == PrefValueKind::Default) {
|
if (aKind == PrefValueKind::Default) {
|
||||||
rv =
|
rv = pref->SetDefaultValue(
|
||||||
pref->SetDefaultValue(aType, aValue, aFromFile, aIsSticky, &valueChanged);
|
aType, aValue, aIsSticky, aIsLocked, aFromFile, &valueChanged);
|
||||||
} else {
|
} else {
|
||||||
|
MOZ_ASSERT(!aIsLocked); // `locked` is disallowed in user pref files
|
||||||
rv = pref->SetUserValue(aType, aValue, aFromFile, &valueChanged);
|
rv = pref->SetUserValue(aType, aValue, aFromFile, &valueChanged);
|
||||||
}
|
}
|
||||||
if (NS_FAILED(rv)) {
|
if (NS_FAILED(rv)) {
|
||||||
|
@ -1078,7 +1084,8 @@ typedef void (*PrefsParserPrefFn)(const char* aPrefName,
|
||||||
PrefType aType,
|
PrefType aType,
|
||||||
PrefValueKind aKind,
|
PrefValueKind aKind,
|
||||||
PrefValue aValue,
|
PrefValue aValue,
|
||||||
bool aIsSticky);
|
bool aIsSticky,
|
||||||
|
bool aIsLocked);
|
||||||
|
|
||||||
// Keep this in sync with ErrorFn in prefs_parser/src/lib.rs.
|
// Keep this in sync with ErrorFn in prefs_parser/src/lib.rs.
|
||||||
//
|
//
|
||||||
|
@ -1089,6 +1096,7 @@ typedef void (*PrefsParserErrorFn)(const char* aMsg);
|
||||||
// Keep this in sync with prefs_parser_parse() in prefs_parser/src/lib.rs.
|
// Keep this in sync with prefs_parser_parse() in prefs_parser/src/lib.rs.
|
||||||
bool
|
bool
|
||||||
prefs_parser_parse(const char* aPath,
|
prefs_parser_parse(const char* aPath,
|
||||||
|
PrefValueKind aKind,
|
||||||
const char* aBuf,
|
const char* aBuf,
|
||||||
size_t aLen,
|
size_t aLen,
|
||||||
PrefsParserPrefFn aPrefFn,
|
PrefsParserPrefFn aPrefFn,
|
||||||
|
@ -1102,13 +1110,14 @@ public:
|
||||||
~Parser() = default;
|
~Parser() = default;
|
||||||
|
|
||||||
bool Parse(const nsCString& aName,
|
bool Parse(const nsCString& aName,
|
||||||
|
PrefValueKind aKind,
|
||||||
const char* aPath,
|
const char* aPath,
|
||||||
const TimeStamp& aStartTime,
|
const TimeStamp& aStartTime,
|
||||||
const nsCString& aBuf)
|
const nsCString& aBuf)
|
||||||
{
|
{
|
||||||
sNumPrefs = 0;
|
sNumPrefs = 0;
|
||||||
bool ok = prefs_parser_parse(
|
bool ok = prefs_parser_parse(
|
||||||
aPath, aBuf.get(), aBuf.Length(), HandlePref, HandleError);
|
aPath, aKind, aBuf.get(), aBuf.Length(), HandlePref, HandleError);
|
||||||
if (!ok) {
|
if (!ok) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -1130,11 +1139,17 @@ private:
|
||||||
PrefType aType,
|
PrefType aType,
|
||||||
PrefValueKind aKind,
|
PrefValueKind aKind,
|
||||||
PrefValue aValue,
|
PrefValue aValue,
|
||||||
bool aIsSticky)
|
bool aIsSticky,
|
||||||
|
bool aIsLocked)
|
||||||
{
|
{
|
||||||
sNumPrefs++;
|
sNumPrefs++;
|
||||||
pref_SetPref(
|
pref_SetPref(aPrefName,
|
||||||
aPrefName, aType, aKind, aValue, aIsSticky, /* fromFile */ true);
|
aType,
|
||||||
|
aKind,
|
||||||
|
aValue,
|
||||||
|
aIsSticky,
|
||||||
|
aIsLocked,
|
||||||
|
/* fromFile */ true);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void HandleError(const char* aMsg)
|
static void HandleError(const char* aMsg)
|
||||||
|
@ -1166,7 +1181,8 @@ TestParseErrorHandlePref(const char* aPrefName,
|
||||||
PrefType aType,
|
PrefType aType,
|
||||||
PrefValueKind aKind,
|
PrefValueKind aKind,
|
||||||
PrefValue aValue,
|
PrefValue aValue,
|
||||||
bool aIsSticky)
|
bool aIsSticky,
|
||||||
|
bool aIsLocked)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1181,9 +1197,10 @@ TestParseErrorHandleError(const char* aMsg)
|
||||||
|
|
||||||
// Keep this in sync with the declaration in test/gtest/Parser.cpp.
|
// Keep this in sync with the declaration in test/gtest/Parser.cpp.
|
||||||
void
|
void
|
||||||
TestParseError(const char* aText, nsCString& aErrorMsg)
|
TestParseError(PrefValueKind aKind, const char* aText, nsCString& aErrorMsg)
|
||||||
{
|
{
|
||||||
prefs_parser_parse("test",
|
prefs_parser_parse("test",
|
||||||
|
aKind,
|
||||||
aText,
|
aText,
|
||||||
strlen(aText),
|
strlen(aText),
|
||||||
TestParseErrorHandlePref,
|
TestParseErrorHandlePref,
|
||||||
|
@ -2451,7 +2468,7 @@ Preferences::HandleDirty()
|
||||||
}
|
}
|
||||||
|
|
||||||
static nsresult
|
static nsresult
|
||||||
openPrefFile(nsIFile* aFile);
|
openPrefFile(nsIFile* aFile, PrefValueKind aKind);
|
||||||
|
|
||||||
static const char kTelemetryPref[] = "toolkit.telemetry.enabled";
|
static const char kTelemetryPref[] = "toolkit.telemetry.enabled";
|
||||||
static const char kChannelPref[] = "app.update.channel";
|
static const char kChannelPref[] = "app.update.channel";
|
||||||
|
@ -3158,6 +3175,19 @@ Preferences::Observe(nsISupports* aSubject,
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NS_IMETHODIMP
|
||||||
|
Preferences::ReadDefaultPrefsFromFile(nsIFile* aFile)
|
||||||
|
{
|
||||||
|
ENSURE_PARENT_PROCESS("Preferences::ReadDefaultPrefsFromFile", "all prefs");
|
||||||
|
|
||||||
|
if (!aFile) {
|
||||||
|
NS_ERROR("ReadDefaultPrefsFromFile requires a parameter");
|
||||||
|
return NS_ERROR_INVALID_ARG;
|
||||||
|
}
|
||||||
|
|
||||||
|
return openPrefFile(aFile, PrefValueKind::Default);
|
||||||
|
}
|
||||||
|
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
Preferences::ReadUserPrefsFromFile(nsIFile* aFile)
|
Preferences::ReadUserPrefsFromFile(nsIFile* aFile)
|
||||||
{
|
{
|
||||||
|
@ -3168,7 +3198,7 @@ Preferences::ReadUserPrefsFromFile(nsIFile* aFile)
|
||||||
return NS_ERROR_INVALID_ARG;
|
return NS_ERROR_INVALID_ARG;
|
||||||
}
|
}
|
||||||
|
|
||||||
return openPrefFile(aFile);
|
return openPrefFile(aFile, PrefValueKind::User);
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
|
@ -3415,7 +3445,7 @@ Preferences::ReadSavedPrefs()
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
rv = openPrefFile(file);
|
rv = openPrefFile(file, PrefValueKind::User);
|
||||||
if (rv == NS_ERROR_FILE_NOT_FOUND) {
|
if (rv == NS_ERROR_FILE_NOT_FOUND) {
|
||||||
// This is a normal case for new users.
|
// This is a normal case for new users.
|
||||||
Telemetry::ScalarSet(
|
Telemetry::ScalarSet(
|
||||||
|
@ -3444,7 +3474,7 @@ Preferences::ReadUserOverridePrefs()
|
||||||
}
|
}
|
||||||
|
|
||||||
aFile->AppendNative(NS_LITERAL_CSTRING("user.js"));
|
aFile->AppendNative(NS_LITERAL_CSTRING("user.js"));
|
||||||
rv = openPrefFile(aFile);
|
rv = openPrefFile(aFile, PrefValueKind::User);
|
||||||
if (rv != NS_ERROR_FILE_NOT_FOUND) {
|
if (rv != NS_ERROR_FILE_NOT_FOUND) {
|
||||||
// If the file exists and was at least partially read, record that in
|
// If the file exists and was at least partially read, record that in
|
||||||
// telemetry as it may be a sign of pref injection.
|
// telemetry as it may be a sign of pref injection.
|
||||||
|
@ -3586,7 +3616,7 @@ Preferences::WritePrefFile(nsIFile* aFile, SaveMethod aSaveMethod)
|
||||||
}
|
}
|
||||||
|
|
||||||
static nsresult
|
static nsresult
|
||||||
openPrefFile(nsIFile* aFile)
|
openPrefFile(nsIFile* aFile, PrefValueKind aKind)
|
||||||
{
|
{
|
||||||
TimeStamp startTime = TimeStamp::Now();
|
TimeStamp startTime = TimeStamp::Now();
|
||||||
|
|
||||||
|
@ -3602,7 +3632,7 @@ openPrefFile(nsIFile* aFile)
|
||||||
|
|
||||||
Parser parser;
|
Parser parser;
|
||||||
if (!parser.Parse(
|
if (!parser.Parse(
|
||||||
filename, NS_ConvertUTF16toUTF8(path).get(), startTime, data)) {
|
filename, aKind, NS_ConvertUTF16toUTF8(path).get(), startTime, data)) {
|
||||||
return NS_ERROR_FILE_CORRUPTED;
|
return NS_ERROR_FILE_CORRUPTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3703,7 +3733,7 @@ pref_LoadPrefsInDir(nsIFile* aDir,
|
||||||
uint32_t arrayCount = prefFiles.Count();
|
uint32_t arrayCount = prefFiles.Count();
|
||||||
uint32_t i;
|
uint32_t i;
|
||||||
for (i = 0; i < arrayCount; ++i) {
|
for (i = 0; i < arrayCount; ++i) {
|
||||||
rv2 = openPrefFile(prefFiles[i]);
|
rv2 = openPrefFile(prefFiles[i], PrefValueKind::Default);
|
||||||
if (NS_FAILED(rv2)) {
|
if (NS_FAILED(rv2)) {
|
||||||
NS_ERROR("Default pref file not parsed successfully.");
|
NS_ERROR("Default pref file not parsed successfully.");
|
||||||
rv = rv2;
|
rv = rv2;
|
||||||
|
@ -3715,7 +3745,7 @@ pref_LoadPrefsInDir(nsIFile* aDir,
|
||||||
// This may be a sparse array; test before parsing.
|
// This may be a sparse array; test before parsing.
|
||||||
nsIFile* file = specialFiles[i];
|
nsIFile* file = specialFiles[i];
|
||||||
if (file) {
|
if (file) {
|
||||||
rv2 = openPrefFile(file);
|
rv2 = openPrefFile(file, PrefValueKind::Default);
|
||||||
if (NS_FAILED(rv2)) {
|
if (NS_FAILED(rv2)) {
|
||||||
NS_ERROR("Special default pref file not parsed successfully.");
|
NS_ERROR("Special default pref file not parsed successfully.");
|
||||||
rv = rv2;
|
rv = rv2;
|
||||||
|
@ -3736,7 +3766,11 @@ pref_ReadPrefFromJar(nsZipArchive* aJarReader, const char* aName)
|
||||||
URLPreloader::ReadZip(aJarReader, nsDependentCString(aName)));
|
URLPreloader::ReadZip(aJarReader, nsDependentCString(aName)));
|
||||||
|
|
||||||
Parser parser;
|
Parser parser;
|
||||||
if (!parser.Parse(nsDependentCString(aName), aName, startTime, manifest)) {
|
if (!parser.Parse(nsDependentCString(aName),
|
||||||
|
PrefValueKind::Default,
|
||||||
|
aName,
|
||||||
|
startTime,
|
||||||
|
manifest)) {
|
||||||
return NS_ERROR_FILE_CORRUPTED;
|
return NS_ERROR_FILE_CORRUPTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3816,7 +3850,7 @@ Preferences::InitInitialObjects()
|
||||||
rv = greprefsFile->AppendNative(NS_LITERAL_CSTRING("greprefs.js"));
|
rv = greprefsFile->AppendNative(NS_LITERAL_CSTRING("greprefs.js"));
|
||||||
NS_ENSURE_SUCCESS(rv, Err("greprefsFile->AppendNative() failed"));
|
NS_ENSURE_SUCCESS(rv, Err("greprefsFile->AppendNative() failed"));
|
||||||
|
|
||||||
rv = openPrefFile(greprefsFile);
|
rv = openPrefFile(greprefsFile, PrefValueKind::Default);
|
||||||
if (NS_FAILED(rv)) {
|
if (NS_FAILED(rv)) {
|
||||||
NS_WARNING("Error parsing GRE default preferences. Is this an old-style "
|
NS_WARNING("Error parsing GRE default preferences. Is this an old-style "
|
||||||
"embedding app?");
|
"embedding app?");
|
||||||
|
@ -3945,15 +3979,14 @@ Preferences::InitInitialObjects()
|
||||||
bool releaseCandidateOnBeta = false;
|
bool releaseCandidateOnBeta = false;
|
||||||
if (!strcmp(NS_STRINGIFY(MOZ_UPDATE_CHANNEL), "release")) {
|
if (!strcmp(NS_STRINGIFY(MOZ_UPDATE_CHANNEL), "release")) {
|
||||||
nsAutoCString updateChannelPrefValue;
|
nsAutoCString updateChannelPrefValue;
|
||||||
Preferences::GetCString(kChannelPref, updateChannelPrefValue,
|
Preferences::GetCString(
|
||||||
PrefValueKind::Default);
|
kChannelPref, updateChannelPrefValue, PrefValueKind::Default);
|
||||||
releaseCandidateOnBeta = updateChannelPrefValue.EqualsLiteral("beta");
|
releaseCandidateOnBeta = updateChannelPrefValue.EqualsLiteral("beta");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!strcmp(NS_STRINGIFY(MOZ_UPDATE_CHANNEL), "nightly") ||
|
if (!strcmp(NS_STRINGIFY(MOZ_UPDATE_CHANNEL), "nightly") ||
|
||||||
!strcmp(NS_STRINGIFY(MOZ_UPDATE_CHANNEL), "aurora") ||
|
!strcmp(NS_STRINGIFY(MOZ_UPDATE_CHANNEL), "aurora") ||
|
||||||
!strcmp(NS_STRINGIFY(MOZ_UPDATE_CHANNEL), "beta") ||
|
!strcmp(NS_STRINGIFY(MOZ_UPDATE_CHANNEL), "beta") || developerBuild ||
|
||||||
developerBuild ||
|
|
||||||
releaseCandidateOnBeta) {
|
releaseCandidateOnBeta) {
|
||||||
Preferences::SetBoolInAnyProcess(
|
Preferences::SetBoolInAnyProcess(
|
||||||
kTelemetryPref, true, PrefValueKind::Default);
|
kTelemetryPref, true, PrefValueKind::Default);
|
||||||
|
@ -4103,6 +4136,7 @@ Preferences::SetCStringInAnyProcess(const char* aPrefName,
|
||||||
aKind,
|
aKind,
|
||||||
prefValue,
|
prefValue,
|
||||||
/* isSticky */ false,
|
/* isSticky */ false,
|
||||||
|
/* isLocked */ false,
|
||||||
/* fromFile */ false);
|
/* fromFile */ false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4129,6 +4163,7 @@ Preferences::SetBoolInAnyProcess(const char* aPrefName,
|
||||||
aKind,
|
aKind,
|
||||||
prefValue,
|
prefValue,
|
||||||
/* isSticky */ false,
|
/* isSticky */ false,
|
||||||
|
/* isLocked */ false,
|
||||||
/* fromFile */ false);
|
/* fromFile */ false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4153,6 +4188,7 @@ Preferences::SetIntInAnyProcess(const char* aPrefName,
|
||||||
aKind,
|
aKind,
|
||||||
prefValue,
|
prefValue,
|
||||||
/* isSticky */ false,
|
/* isSticky */ false,
|
||||||
|
/* isLocked */ false,
|
||||||
/* fromFile */ false);
|
/* fromFile */ false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4185,7 +4221,6 @@ Preferences::LockInAnyProcess(const char* aPrefName)
|
||||||
|
|
||||||
if (!pref->IsLocked()) {
|
if (!pref->IsLocked()) {
|
||||||
pref->SetIsLocked(true);
|
pref->SetIsLocked(true);
|
||||||
gIsAnyPrefLocked = true;
|
|
||||||
NotifyCallbacks(aPrefName);
|
NotifyCallbacks(aPrefName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4223,14 +4258,8 @@ Preferences::IsLocked(const char* aPrefName)
|
||||||
{
|
{
|
||||||
NS_ENSURE_TRUE(InitStaticMembers(), false);
|
NS_ENSURE_TRUE(InitStaticMembers(), false);
|
||||||
|
|
||||||
if (gIsAnyPrefLocked) {
|
Pref* pref = pref_HashTableLookup(aPrefName);
|
||||||
Pref* pref = pref_HashTableLookup(aPrefName);
|
return pref && pref->IsLocked();
|
||||||
if (pref && pref->IsLocked()) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* static */ nsresult
|
/* static */ nsresult
|
||||||
|
|
|
@ -1089,23 +1089,23 @@ pref("devtools.errorconsole.deprecation_warnings", true);
|
||||||
|
|
||||||
#ifdef NIGHTLY_BUILD
|
#ifdef NIGHTLY_BUILD
|
||||||
// Don't show the Browser Toolbox prompt on local builds / nightly
|
// Don't show the Browser Toolbox prompt on local builds / nightly
|
||||||
sticky_pref("devtools.debugger.prompt-connection", false);
|
pref("devtools.debugger.prompt-connection", false, sticky);
|
||||||
#else
|
#else
|
||||||
sticky_pref("devtools.debugger.prompt-connection", true);
|
pref("devtools.debugger.prompt-connection", true, sticky);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef MOZILLA_OFFICIAL
|
#ifdef MOZILLA_OFFICIAL
|
||||||
// Disable debugging chrome
|
// Disable debugging chrome
|
||||||
sticky_pref("devtools.chrome.enabled", false);
|
pref("devtools.chrome.enabled", false, sticky);
|
||||||
// Disable remote debugging connections
|
// Disable remote debugging connections
|
||||||
sticky_pref("devtools.debugger.remote-enabled", false);
|
pref("devtools.debugger.remote-enabled", false, sticky);
|
||||||
// enable JS dump() function.
|
// enable JS dump() function.
|
||||||
sticky_pref("browser.dom.window.dump.enabled", false);
|
pref("browser.dom.window.dump.enabled", false, sticky);
|
||||||
#else
|
#else
|
||||||
// In local builds, enable the browser toolbox by default
|
// In local builds, enable the browser toolbox by default
|
||||||
sticky_pref("devtools.chrome.enabled", true);
|
pref("devtools.chrome.enabled", true, sticky);
|
||||||
sticky_pref("devtools.debugger.remote-enabled", true);
|
pref("devtools.debugger.remote-enabled", true, sticky);
|
||||||
sticky_pref("browser.dom.window.dump.enabled", true);
|
pref("browser.dom.window.dump.enabled", true, sticky);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -45,7 +45,7 @@ interface nsIPrefService : nsISupports
|
||||||
*
|
*
|
||||||
* @throws Error File failed to write.
|
* @throws Error File failed to write.
|
||||||
*
|
*
|
||||||
* @see readUserPrefs
|
* @see readUserPrefsFromFile
|
||||||
* @see nsIFile
|
* @see nsIFile
|
||||||
*/
|
*/
|
||||||
void savePrefFile(in nsIFile aFile);
|
void savePrefFile(in nsIFile aFile);
|
||||||
|
@ -102,14 +102,20 @@ interface nsIPrefService : nsISupports
|
||||||
readonly attribute boolean dirty;
|
readonly attribute boolean dirty;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Read in the preferences specified in a user preference file. This method
|
* Read in the preferences specified in a default preference file. This
|
||||||
* does not clear user preferences that were already set.
|
* method does not clear preferences that were already set, but it may
|
||||||
|
* overwrite existing preferences.
|
||||||
*
|
*
|
||||||
* @param aFile The file to be read.
|
* @param aFile The file to be read.
|
||||||
*
|
*
|
||||||
* @throws Error File failed to read or contained invalid data.
|
* @throws Error File failed to read or contained invalid data.
|
||||||
* @note This method is intended for internal unit testing only!
|
* @note This method is intended for internal unit testing only!
|
||||||
*/
|
*/
|
||||||
|
void readDefaultPrefsFromFile(in nsIFile aFile);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Like readDefaultPrefsFromFile, but for a user prefs file.
|
||||||
|
*/
|
||||||
void readUserPrefsFromFile(in nsIFile aFile);
|
void readUserPrefsFromFile(in nsIFile aFile);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -4,10 +4,12 @@
|
||||||
|
|
||||||
//! This crate implements a prefs file parser.
|
//! This crate implements a prefs file parser.
|
||||||
//!
|
//!
|
||||||
//! Pref files have the following grammar.
|
//! Pref files have the following grammar. Note that there are slight
|
||||||
|
//! differences between the grammar for a default prefs files and a user prefs
|
||||||
|
//! file.
|
||||||
//!
|
//!
|
||||||
//! <pref-file> = <pref>*
|
//! <pref-file> = <pref>*
|
||||||
//! <pref> = <pref-spec> "(" <pref-name> "," <pref-value> ")" ";"
|
//! <pref> = <pref-spec> "(" <pref-name> "," <pref-value> <pref-attrs> ")" ";"
|
||||||
//! <pref-spec> = "user_pref" | "pref" | "sticky_pref"
|
//! <pref-spec> = "user_pref" | "pref" | "sticky_pref"
|
||||||
//! <pref-name> = <string-literal>
|
//! <pref-name> = <string-literal>
|
||||||
//! <pref-value> = <string-literal> | "true" | "false" | <int-value>
|
//! <pref-value> = <string-literal> | "true" | "false" | <int-value>
|
||||||
|
@ -21,6 +23,9 @@
|
||||||
//! gives a UTF-16 code unit that is converted to UTF-8 before being copied
|
//! gives a UTF-16 code unit that is converted to UTF-8 before being copied
|
||||||
//! into an 8-bit string value. \x00 and \u0000 are disallowed because they
|
//! into an 8-bit string value. \x00 and \u0000 are disallowed because they
|
||||||
//! would cause C++ code handling such strings to misbehave.
|
//! would cause C++ code handling such strings to misbehave.
|
||||||
|
//! <pref-attrs> = ("," <pref-attr>)* // in default pref files
|
||||||
|
//! = <empty> // in user pref files
|
||||||
|
//! <pref-attr> = "sticky" | "locked" // default pref files only
|
||||||
//!
|
//!
|
||||||
//! Comments can take three forms:
|
//! Comments can take three forms:
|
||||||
//! - # Python-style comments
|
//! - # Python-style comments
|
||||||
|
@ -94,7 +99,7 @@ pub enum PrefType {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Keep this in sync with PrefValueKind in Preferences.h.
|
/// Keep this in sync with PrefValueKind in Preferences.h.
|
||||||
#[derive(Clone, Copy, Debug)]
|
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||||
#[repr(u8)]
|
#[repr(u8)]
|
||||||
pub enum PrefValueKind {
|
pub enum PrefValueKind {
|
||||||
Default,
|
Default,
|
||||||
|
@ -112,7 +117,7 @@ pub union PrefValue {
|
||||||
/// Keep this in sync with PrefsParserPrefFn in Preferences.cpp.
|
/// Keep this in sync with PrefsParserPrefFn in Preferences.cpp.
|
||||||
type PrefFn = unsafe extern "C" fn(pref_name: *const c_char, pref_type: PrefType,
|
type PrefFn = unsafe extern "C" fn(pref_name: *const c_char, pref_type: PrefType,
|
||||||
pref_value_kind: PrefValueKind, pref_value: PrefValue,
|
pref_value_kind: PrefValueKind, pref_value: PrefValue,
|
||||||
is_sticky: bool);
|
is_sticky: bool, is_locked: bool);
|
||||||
|
|
||||||
/// Keep this in sync with PrefsParserErrorFn in Preferences.cpp.
|
/// Keep this in sync with PrefsParserErrorFn in Preferences.cpp.
|
||||||
type ErrorFn = unsafe extern "C" fn(msg: *const c_char);
|
type ErrorFn = unsafe extern "C" fn(msg: *const c_char);
|
||||||
|
@ -129,8 +134,8 @@ type ErrorFn = unsafe extern "C" fn(msg: *const c_char);
|
||||||
/// Keep this in sync with the prefs_parser_parse() declaration in
|
/// Keep this in sync with the prefs_parser_parse() declaration in
|
||||||
/// Preferences.cpp.
|
/// Preferences.cpp.
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub extern "C" fn prefs_parser_parse(path: *const c_char, buf: *const c_char, len: usize,
|
pub extern "C" fn prefs_parser_parse(path: *const c_char, kind: PrefValueKind, buf: *const c_char,
|
||||||
pref_fn: PrefFn, error_fn: ErrorFn) -> bool {
|
len: usize, pref_fn: PrefFn, error_fn: ErrorFn) -> bool {
|
||||||
let path = unsafe { std::ffi::CStr::from_ptr(path).to_string_lossy().into_owned() };
|
let path = unsafe { std::ffi::CStr::from_ptr(path).to_string_lossy().into_owned() };
|
||||||
|
|
||||||
// Make sure `buf` ends in a '\0', and include that in the length, because
|
// Make sure `buf` ends in a '\0', and include that in the length, because
|
||||||
|
@ -138,7 +143,7 @@ pub extern "C" fn prefs_parser_parse(path: *const c_char, buf: *const c_char, le
|
||||||
let buf = unsafe { std::slice::from_raw_parts(buf as *const c_uchar, len + 1) };
|
let buf = unsafe { std::slice::from_raw_parts(buf as *const c_uchar, len + 1) };
|
||||||
assert!(buf.last() == Some(&EOF));
|
assert!(buf.last() == Some(&EOF));
|
||||||
|
|
||||||
let mut parser = Parser::new(&path, &buf, pref_fn, error_fn);
|
let mut parser = Parser::new(&path, kind, &buf, pref_fn, error_fn);
|
||||||
parser.parse()
|
parser.parse()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -157,6 +162,8 @@ enum Token {
|
||||||
UserPref, // user_pref
|
UserPref, // user_pref
|
||||||
True, // true
|
True, // true
|
||||||
False, // false
|
False, // false
|
||||||
|
Sticky, // sticky
|
||||||
|
Locked, // locked
|
||||||
|
|
||||||
// String literal, e.g. '"string"'. The value is stored elsewhere.
|
// String literal, e.g. '"string"'. The value is stored elsewhere.
|
||||||
String,
|
String,
|
||||||
|
@ -272,36 +279,41 @@ struct KeywordInfo {
|
||||||
token: Token,
|
token: Token,
|
||||||
}
|
}
|
||||||
|
|
||||||
const KEYWORD_INFOS: &[KeywordInfo; 5] = &[
|
const KEYWORD_INFOS: [KeywordInfo; 7] = [
|
||||||
// These are ordered by frequency.
|
// These are ordered by frequency.
|
||||||
KeywordInfo { string: b"pref", token: Token::Pref },
|
KeywordInfo { string: b"pref", token: Token::Pref },
|
||||||
KeywordInfo { string: b"true", token: Token::True },
|
KeywordInfo { string: b"true", token: Token::True },
|
||||||
KeywordInfo { string: b"false", token: Token::False },
|
KeywordInfo { string: b"false", token: Token::False },
|
||||||
KeywordInfo { string: b"user_pref", token: Token::UserPref },
|
KeywordInfo { string: b"user_pref", token: Token::UserPref },
|
||||||
|
KeywordInfo { string: b"sticky", token: Token::Sticky },
|
||||||
|
KeywordInfo { string: b"locked", token: Token::Locked },
|
||||||
KeywordInfo { string: b"sticky_pref", token: Token::StickyPref },
|
KeywordInfo { string: b"sticky_pref", token: Token::StickyPref },
|
||||||
];
|
];
|
||||||
|
|
||||||
struct Parser<'t> {
|
struct Parser<'t> {
|
||||||
path: &'t str, // Path to the file being parsed. Used in error messages.
|
path: &'t str, // Path to the file being parsed. Used in error messages.
|
||||||
buf: &'t [u8], // Text being parsed.
|
kind: PrefValueKind, // Default prefs file or user prefs file?
|
||||||
i: usize, // Index of next char to be read.
|
buf: &'t [u8], // Text being parsed.
|
||||||
line_num: u32, // Current line number within the text.
|
i: usize, // Index of next char to be read.
|
||||||
pref_fn: PrefFn, // Callback for processing each pref.
|
line_num: u32, // Current line number within the text.
|
||||||
error_fn: ErrorFn, // Callback for parse errors.
|
pref_fn: PrefFn, // Callback for processing each pref.
|
||||||
has_errors: bool, // Have we encountered errors?
|
error_fn: ErrorFn, // Callback for parse errors.
|
||||||
|
has_errors: bool, // Have we encountered errors?
|
||||||
}
|
}
|
||||||
|
|
||||||
// As described above, we use 0 to represent EOF.
|
// As described above, we use 0 to represent EOF.
|
||||||
const EOF: u8 = b'\0';
|
const EOF: u8 = b'\0';
|
||||||
|
|
||||||
impl<'t> Parser<'t> {
|
impl<'t> Parser<'t> {
|
||||||
fn new(path: &'t str, buf: &'t [u8], pref_fn: PrefFn, error_fn: ErrorFn) -> Parser<'t> {
|
fn new(path: &'t str, kind: PrefValueKind, buf: &'t [u8], pref_fn: PrefFn, error_fn: ErrorFn)
|
||||||
|
-> Parser<'t> {
|
||||||
// Make sure these tables take up 1 byte per entry.
|
// Make sure these tables take up 1 byte per entry.
|
||||||
assert!(std::mem::size_of_val(&CHAR_KINDS) == 256);
|
assert!(std::mem::size_of_val(&CHAR_KINDS) == 256);
|
||||||
assert!(std::mem::size_of_val(&SPECIAL_STRING_CHARS) == 256);
|
assert!(std::mem::size_of_val(&SPECIAL_STRING_CHARS) == 256);
|
||||||
|
|
||||||
Parser {
|
Parser {
|
||||||
path: path,
|
path: path,
|
||||||
|
kind: kind,
|
||||||
buf: buf,
|
buf: buf,
|
||||||
i: 0,
|
i: 0,
|
||||||
line_num: 1,
|
line_num: 1,
|
||||||
|
@ -323,7 +335,7 @@ impl<'t> Parser<'t> {
|
||||||
// this will be either the first token of a new pref, or EOF.
|
// this will be either the first token of a new pref, or EOF.
|
||||||
loop {
|
loop {
|
||||||
// <pref-spec>
|
// <pref-spec>
|
||||||
let (pref_value_kind, is_sticky) = match token {
|
let (pref_value_kind, mut is_sticky) = match token {
|
||||||
Token::Pref => (PrefValueKind::Default, false),
|
Token::Pref => (PrefValueKind::Default, false),
|
||||||
Token::StickyPref => (PrefValueKind::Default, true),
|
Token::StickyPref => (PrefValueKind::Default, true),
|
||||||
Token::UserPref => (PrefValueKind::User, false),
|
Token::UserPref => (PrefValueKind::User, false),
|
||||||
|
@ -370,7 +382,6 @@ impl<'t> Parser<'t> {
|
||||||
Token::String => {
|
Token::String => {
|
||||||
(PrefType::String,
|
(PrefType::String,
|
||||||
PrefValue { string_val: value_str.as_ptr() as *const c_char })
|
PrefValue { string_val: value_str.as_ptr() as *const c_char })
|
||||||
|
|
||||||
}
|
}
|
||||||
Token::Int(u) => {
|
Token::Int(u) => {
|
||||||
// Accept u <= 2147483647; anything larger will overflow i32.
|
// Accept u <= 2147483647; anything larger will overflow i32.
|
||||||
|
@ -425,10 +436,49 @@ impl<'t> Parser<'t> {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// ("," <pref-attr>)* // default pref files only
|
||||||
|
let mut is_locked = false;
|
||||||
|
let mut has_attrs = false;
|
||||||
|
if self.kind == PrefValueKind::Default {
|
||||||
|
let ok = loop {
|
||||||
|
// ","
|
||||||
|
token = self.get_token(&mut none_str);
|
||||||
|
if token != Token::SingleChar(b',') {
|
||||||
|
break true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// <pref-attr>
|
||||||
|
token = self.get_token(&mut none_str);
|
||||||
|
match token {
|
||||||
|
Token::Sticky => is_sticky = true,
|
||||||
|
Token::Locked => is_locked = true,
|
||||||
|
_ => {
|
||||||
|
token =
|
||||||
|
self.error_and_recover(token, "expected pref attribute after ','");
|
||||||
|
break false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
has_attrs = true;
|
||||||
|
};
|
||||||
|
if !ok {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
token = self.get_token(&mut none_str);
|
||||||
|
}
|
||||||
|
|
||||||
// ")"
|
// ")"
|
||||||
token = self.get_token(&mut none_str);
|
|
||||||
if token != Token::SingleChar(b')') {
|
if token != Token::SingleChar(b')') {
|
||||||
token = self.error_and_recover(token, "expected ')' after pref value");
|
let expected_msg = if self.kind == PrefValueKind::Default {
|
||||||
|
if has_attrs {
|
||||||
|
"expected ',' or ')' after pref attribute"
|
||||||
|
} else {
|
||||||
|
"expected ',' or ')' after pref value"
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
"expected ')' after pref value"
|
||||||
|
};
|
||||||
|
token = self.error_and_recover(token, expected_msg);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -440,7 +490,7 @@ impl<'t> Parser<'t> {
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe { (self.pref_fn)(pref_name.as_ptr() as *const c_char, pref_type, pref_value_kind,
|
unsafe { (self.pref_fn)(pref_name.as_ptr() as *const c_char, pref_type, pref_value_kind,
|
||||||
pref_value, is_sticky) };
|
pref_value, is_sticky, is_locked) };
|
||||||
|
|
||||||
token = self.get_token(&mut none_str);
|
token = self.get_token(&mut none_str);
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,12 +6,15 @@
|
||||||
|
|
||||||
#include "gtest/gtest.h"
|
#include "gtest/gtest.h"
|
||||||
#include "mozilla/ArrayUtils.h"
|
#include "mozilla/ArrayUtils.h"
|
||||||
|
#include "Preferences.h"
|
||||||
|
|
||||||
|
using namespace mozilla;
|
||||||
|
|
||||||
// Keep this in sync with the declaration in Preferences.cpp.
|
// Keep this in sync with the declaration in Preferences.cpp.
|
||||||
//
|
//
|
||||||
// It's declared here to avoid polluting Preferences.h with test-only stuff.
|
// It's declared here to avoid polluting Preferences.h with test-only stuff.
|
||||||
void
|
void
|
||||||
TestParseError(const char* aText, nsCString& aErrorMsg);
|
TestParseError(PrefValueKind aKind, const char* aText, nsCString& aErrorMsg);
|
||||||
|
|
||||||
TEST(PrefsParser, Errors)
|
TEST(PrefsParser, Errors)
|
||||||
{
|
{
|
||||||
|
@ -19,12 +22,18 @@ TEST(PrefsParser, Errors)
|
||||||
|
|
||||||
// Use a macro rather than a function so that the line number reported by
|
// Use a macro rather than a function so that the line number reported by
|
||||||
// gtest on failure is useful.
|
// gtest on failure is useful.
|
||||||
#define P(text_, expectedErrorMsg_) \
|
#define P(kind_, text_, expectedErrorMsg_) \
|
||||||
do { \
|
do { \
|
||||||
TestParseError(text_, actualErrorMsg); \
|
TestParseError(kind_, text_, actualErrorMsg); \
|
||||||
ASSERT_STREQ(expectedErrorMsg_, actualErrorMsg.get()); \
|
ASSERT_STREQ(expectedErrorMsg_, actualErrorMsg.get()); \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
|
#define DEFAULT(text_, expectedErrorMsg_) \
|
||||||
|
P(PrefValueKind::Default, text_, expectedErrorMsg_)
|
||||||
|
|
||||||
|
#define USER(text_, expectedErrorMsg_) \
|
||||||
|
P(PrefValueKind::User, text_, expectedErrorMsg_)
|
||||||
|
|
||||||
// clang-format off
|
// clang-format off
|
||||||
|
|
||||||
//-------------------------------------------------------------------------
|
//-------------------------------------------------------------------------
|
||||||
|
@ -33,7 +42,7 @@ TEST(PrefsParser, Errors)
|
||||||
//-------------------------------------------------------------------------
|
//-------------------------------------------------------------------------
|
||||||
|
|
||||||
// Normal prefs.
|
// Normal prefs.
|
||||||
P(R"(
|
DEFAULT(R"(
|
||||||
pref("bool", true);
|
pref("bool", true);
|
||||||
sticky_pref("int", 123);
|
sticky_pref("int", 123);
|
||||||
user_pref("string", "value");
|
user_pref("string", "value");
|
||||||
|
@ -42,12 +51,12 @@ user_pref("string", "value");
|
||||||
);
|
);
|
||||||
|
|
||||||
// Totally empty input.
|
// Totally empty input.
|
||||||
P("",
|
DEFAULT("",
|
||||||
""
|
""
|
||||||
);
|
);
|
||||||
|
|
||||||
// Whitespace-only input.
|
// Whitespace-only input.
|
||||||
P(R"(
|
DEFAULT(R"(
|
||||||
|
|
||||||
)" "\v \t \v \f",
|
)" "\v \t \v \f",
|
||||||
""
|
""
|
||||||
|
@ -60,7 +69,7 @@ user_pref("string", "value");
|
||||||
//-------------------------------------------------------------------------
|
//-------------------------------------------------------------------------
|
||||||
|
|
||||||
// Integer overflow errors.
|
// Integer overflow errors.
|
||||||
P(R"(
|
DEFAULT(R"(
|
||||||
pref("int.ok", 2147483647);
|
pref("int.ok", 2147483647);
|
||||||
pref("int.overflow", 2147483648);
|
pref("int.overflow", 2147483648);
|
||||||
pref("int.ok", +2147483647);
|
pref("int.ok", +2147483647);
|
||||||
|
@ -84,7 +93,7 @@ pref("int.overflow", 1234567890987654321);
|
||||||
);
|
);
|
||||||
|
|
||||||
// Other integer errors.
|
// Other integer errors.
|
||||||
P(R"(
|
DEFAULT(R"(
|
||||||
pref("int.unexpected", 100foo);
|
pref("int.unexpected", 100foo);
|
||||||
pref("int.ok", 0);
|
pref("int.ok", 0);
|
||||||
)",
|
)",
|
||||||
|
@ -92,7 +101,7 @@ pref("int.ok", 0);
|
||||||
);
|
);
|
||||||
|
|
||||||
// \x00 is not allowed.
|
// \x00 is not allowed.
|
||||||
P(R"(
|
DEFAULT(R"(
|
||||||
pref("string.bad-x-escape", "foo\x00bar");
|
pref("string.bad-x-escape", "foo\x00bar");
|
||||||
pref("int.ok", 0);
|
pref("int.ok", 0);
|
||||||
)",
|
)",
|
||||||
|
@ -101,7 +110,7 @@ pref("int.ok", 0);
|
||||||
|
|
||||||
// Various bad things after \x: end of string, punctuation, space, newline,
|
// Various bad things after \x: end of string, punctuation, space, newline,
|
||||||
// EOF.
|
// EOF.
|
||||||
P(R"(
|
DEFAULT(R"(
|
||||||
pref("string.bad-x-escape", "foo\x");
|
pref("string.bad-x-escape", "foo\x");
|
||||||
pref("string.bad-x-escape", "foo\x,bar");
|
pref("string.bad-x-escape", "foo\x,bar");
|
||||||
pref("string.bad-x-escape", "foo\x 12");
|
pref("string.bad-x-escape", "foo\x 12");
|
||||||
|
@ -116,7 +125,7 @@ pref("string.bad-x-escape", "foo\x)",
|
||||||
);
|
);
|
||||||
|
|
||||||
// Not enough hex digits.
|
// Not enough hex digits.
|
||||||
P(R"(
|
DEFAULT(R"(
|
||||||
pref("string.bad-x-escape", "foo\x1");
|
pref("string.bad-x-escape", "foo\x1");
|
||||||
pref("int.ok", 0);
|
pref("int.ok", 0);
|
||||||
)",
|
)",
|
||||||
|
@ -124,7 +133,7 @@ pref("int.ok", 0);
|
||||||
);
|
);
|
||||||
|
|
||||||
// Invalid hex digit.
|
// Invalid hex digit.
|
||||||
P(R"(
|
DEFAULT(R"(
|
||||||
pref("string.bad-x-escape", "foo\x1G");
|
pref("string.bad-x-escape", "foo\x1G");
|
||||||
pref("int.ok", 0);
|
pref("int.ok", 0);
|
||||||
)",
|
)",
|
||||||
|
@ -134,7 +143,7 @@ pref("int.ok", 0);
|
||||||
// \u0000 is not allowed.
|
// \u0000 is not allowed.
|
||||||
// (The string literal is broken in two so that MSVC doesn't complain about
|
// (The string literal is broken in two so that MSVC doesn't complain about
|
||||||
// an invalid universal-character-name.)
|
// an invalid universal-character-name.)
|
||||||
P(R"(
|
DEFAULT(R"(
|
||||||
pref("string.bad-u-escape", "foo\)" R"(u0000 bar");
|
pref("string.bad-u-escape", "foo\)" R"(u0000 bar");
|
||||||
pref("int.ok", 0);
|
pref("int.ok", 0);
|
||||||
)",
|
)",
|
||||||
|
@ -143,7 +152,7 @@ pref("int.ok", 0);
|
||||||
|
|
||||||
// Various bad things after \u: end of string, punctuation, space, newline,
|
// Various bad things after \u: end of string, punctuation, space, newline,
|
||||||
// EOF.
|
// EOF.
|
||||||
P(R"(
|
DEFAULT(R"(
|
||||||
pref("string.bad-u-escape", "foo\u");
|
pref("string.bad-u-escape", "foo\u");
|
||||||
pref("string.bad-u-escape", "foo\u,bar");
|
pref("string.bad-u-escape", "foo\u,bar");
|
||||||
pref("string.bad-u-escape", "foo\u 1234");
|
pref("string.bad-u-escape", "foo\u 1234");
|
||||||
|
@ -158,7 +167,7 @@ pref("string.bad-u-escape", "foo\u)",
|
||||||
);
|
);
|
||||||
|
|
||||||
// Not enough hex digits.
|
// Not enough hex digits.
|
||||||
P(R"(
|
DEFAULT(R"(
|
||||||
pref("string.bad-u-escape", "foo\u1");
|
pref("string.bad-u-escape", "foo\u1");
|
||||||
pref("string.bad-u-escape", "foo\u12");
|
pref("string.bad-u-escape", "foo\u12");
|
||||||
pref("string.bad-u-escape", "foo\u123");
|
pref("string.bad-u-escape", "foo\u123");
|
||||||
|
@ -170,7 +179,7 @@ pref("int.ok", 0);
|
||||||
);
|
);
|
||||||
|
|
||||||
// Invalid hex digit.
|
// Invalid hex digit.
|
||||||
P(R"(
|
DEFAULT(R"(
|
||||||
pref("string.bad-u-escape", "foo\u1G34");
|
pref("string.bad-u-escape", "foo\u1G34");
|
||||||
pref("int.ok", 0);
|
pref("int.ok", 0);
|
||||||
)",
|
)",
|
||||||
|
@ -180,7 +189,7 @@ pref("int.ok", 0);
|
||||||
// High surrogate not followed by low surrogate.
|
// High surrogate not followed by low surrogate.
|
||||||
// (The string literal is broken in two so that MSVC doesn't complain about
|
// (The string literal is broken in two so that MSVC doesn't complain about
|
||||||
// an invalid universal-character-name.)
|
// an invalid universal-character-name.)
|
||||||
P(R"(
|
DEFAULT(R"(
|
||||||
pref("string.bad-u-surrogate", "foo\)" R"(ud83c,blah");
|
pref("string.bad-u-surrogate", "foo\)" R"(ud83c,blah");
|
||||||
pref("int.ok", 0);
|
pref("int.ok", 0);
|
||||||
)",
|
)",
|
||||||
|
@ -190,7 +199,7 @@ pref("int.ok", 0);
|
||||||
// High surrogate followed by invalid low surrogate value.
|
// High surrogate followed by invalid low surrogate value.
|
||||||
// (The string literal is broken in two so that MSVC doesn't complain about
|
// (The string literal is broken in two so that MSVC doesn't complain about
|
||||||
// an invalid universal-character-name.)
|
// an invalid universal-character-name.)
|
||||||
P(R"(
|
DEFAULT(R"(
|
||||||
pref("string.bad-u-surrogate", "foo\)" R"(ud83c\u1234");
|
pref("string.bad-u-surrogate", "foo\)" R"(ud83c\u1234");
|
||||||
pref("int.ok", 0);
|
pref("int.ok", 0);
|
||||||
)",
|
)",
|
||||||
|
@ -198,7 +207,7 @@ pref("int.ok", 0);
|
||||||
);
|
);
|
||||||
|
|
||||||
// Unlike in JavaScript, \b, \f, \t, \v aren't allowed.
|
// Unlike in JavaScript, \b, \f, \t, \v aren't allowed.
|
||||||
P(R"(
|
DEFAULT(R"(
|
||||||
pref("string.bad-escape", "foo\b");
|
pref("string.bad-escape", "foo\b");
|
||||||
pref("string.bad-escape", "foo\f");
|
pref("string.bad-escape", "foo\f");
|
||||||
pref("string.bad-escape", "foo\t");
|
pref("string.bad-escape", "foo\t");
|
||||||
|
@ -213,7 +222,7 @@ pref("int.ok", 0);
|
||||||
|
|
||||||
// Various bad things after \: non-special letter, number, punctuation,
|
// Various bad things after \: non-special letter, number, punctuation,
|
||||||
// space, newline, EOF.
|
// space, newline, EOF.
|
||||||
P(R"(
|
DEFAULT(R"(
|
||||||
pref("string.bad-escape", "foo\Q");
|
pref("string.bad-escape", "foo\Q");
|
||||||
pref("string.bad-escape", "foo\1");
|
pref("string.bad-escape", "foo\1");
|
||||||
pref("string.bad-escape", "foo\,");
|
pref("string.bad-escape", "foo\,");
|
||||||
|
@ -232,7 +241,7 @@ pref("string.bad-escape", "foo\)",
|
||||||
// Unterminated string literals.
|
// Unterminated string literals.
|
||||||
|
|
||||||
// Simple case.
|
// Simple case.
|
||||||
P(R"(
|
DEFAULT(R"(
|
||||||
pref("string.unterminated-string", "foo
|
pref("string.unterminated-string", "foo
|
||||||
)",
|
)",
|
||||||
"test:3: prefs parse error: unterminated string literal\n"
|
"test:3: prefs parse error: unterminated string literal\n"
|
||||||
|
@ -241,7 +250,7 @@ pref("string.unterminated-string", "foo
|
||||||
// Alternative case; `int` comes after the string and is seen as a keyword.
|
// Alternative case; `int` comes after the string and is seen as a keyword.
|
||||||
// The parser then skips to the ';', so no error about the unterminated
|
// The parser then skips to the ';', so no error about the unterminated
|
||||||
// string is issued.
|
// string is issued.
|
||||||
P(R"(
|
DEFAULT(R"(
|
||||||
pref("string.unterminated-string", "foo);
|
pref("string.unterminated-string", "foo);
|
||||||
pref("int.ok", 0);
|
pref("int.ok", 0);
|
||||||
)",
|
)",
|
||||||
|
@ -249,21 +258,21 @@ pref("int.ok", 0);
|
||||||
);
|
);
|
||||||
|
|
||||||
// Mismatched quotes (1).
|
// Mismatched quotes (1).
|
||||||
P(R"(
|
DEFAULT(R"(
|
||||||
pref("string.unterminated-string", "foo');
|
pref("string.unterminated-string", "foo');
|
||||||
)",
|
)",
|
||||||
"test:3: prefs parse error: unterminated string literal\n"
|
"test:3: prefs parse error: unterminated string literal\n"
|
||||||
);
|
);
|
||||||
|
|
||||||
// Mismatched quotes (2).
|
// Mismatched quotes (2).
|
||||||
P(R"(
|
DEFAULT(R"(
|
||||||
pref("string.unterminated-string", 'foo");
|
pref("string.unterminated-string", 'foo");
|
||||||
)",
|
)",
|
||||||
"test:3: prefs parse error: unterminated string literal\n"
|
"test:3: prefs parse error: unterminated string literal\n"
|
||||||
);
|
);
|
||||||
|
|
||||||
// Unknown keywords.
|
// Unknown keywords.
|
||||||
P(R"(
|
DEFAULT(R"(
|
||||||
foo;
|
foo;
|
||||||
preff("string.bad-keyword", true);
|
preff("string.bad-keyword", true);
|
||||||
ticky_pref("string.bad-keyword", true);
|
ticky_pref("string.bad-keyword", true);
|
||||||
|
@ -278,33 +287,33 @@ pref("string.bad-keyword", TRUE);
|
||||||
);
|
);
|
||||||
|
|
||||||
// Unterminated C-style comment.
|
// Unterminated C-style comment.
|
||||||
P(R"(
|
DEFAULT(R"(
|
||||||
/* comment
|
/* comment
|
||||||
)",
|
)",
|
||||||
"test:3: prefs parse error: unterminated /* comment\n"
|
"test:3: prefs parse error: unterminated /* comment\n"
|
||||||
);
|
);
|
||||||
|
|
||||||
// Malformed comment.
|
// Malformed comment.
|
||||||
P(R"(
|
DEFAULT(R"(
|
||||||
/ comment
|
/ comment
|
||||||
)",
|
)",
|
||||||
"test:2: prefs parse error: expected '/' or '*' after '/'\n"
|
"test:2: prefs parse error: expected '/' or '*' after '/'\n"
|
||||||
);
|
);
|
||||||
|
|
||||||
// C++-style comment ending in EOF (1).
|
// C++-style comment ending in EOF (1).
|
||||||
P(R"(
|
DEFAULT(R"(
|
||||||
// comment)",
|
// comment)",
|
||||||
""
|
""
|
||||||
);
|
);
|
||||||
|
|
||||||
// C++-style comment ending in EOF (2).
|
// C++-style comment ending in EOF (2).
|
||||||
P(R"(
|
DEFAULT(R"(
|
||||||
//)",
|
//)",
|
||||||
""
|
""
|
||||||
);
|
);
|
||||||
|
|
||||||
// Various unexpected characters.
|
// Various unexpected characters.
|
||||||
P(R"(
|
DEFAULT(R"(
|
||||||
pref("unexpected.chars", &true);
|
pref("unexpected.chars", &true);
|
||||||
pref("unexpected.chars" : true);
|
pref("unexpected.chars" : true);
|
||||||
@pref("unexpected.chars", true);
|
@pref("unexpected.chars", true);
|
||||||
|
@ -320,7 +329,7 @@ pref["unexpected.chars": true];
|
||||||
// All the parsing errors.
|
// All the parsing errors.
|
||||||
//-------------------------------------------------------------------------
|
//-------------------------------------------------------------------------
|
||||||
|
|
||||||
P(R"(
|
DEFAULT(R"(
|
||||||
"pref"("parse.error": true);
|
"pref"("parse.error": true);
|
||||||
pref1("parse.error": true);
|
pref1("parse.error": true);
|
||||||
pref(123: true);
|
pref(123: true);
|
||||||
|
@ -328,7 +337,9 @@ pref("parse.error" true);
|
||||||
pref("parse.error", pref);
|
pref("parse.error", pref);
|
||||||
pref("parse.error", -true);
|
pref("parse.error", -true);
|
||||||
pref("parse.error", +"value");
|
pref("parse.error", +"value");
|
||||||
|
pref("parse.error", true,);
|
||||||
pref("parse.error", true;
|
pref("parse.error", true;
|
||||||
|
pref("parse.error", true, sticky, locked;
|
||||||
pref("parse.error", true)
|
pref("parse.error", true)
|
||||||
pref("int.ok", 1);
|
pref("int.ok", 1);
|
||||||
pref("parse.error", true))",
|
pref("parse.error", true))",
|
||||||
|
@ -339,59 +350,83 @@ pref("parse.error", true))",
|
||||||
"test:6: prefs parse error: expected pref value after ','\n"
|
"test:6: prefs parse error: expected pref value after ','\n"
|
||||||
"test:7: prefs parse error: expected integer literal after '-'\n"
|
"test:7: prefs parse error: expected integer literal after '-'\n"
|
||||||
"test:8: prefs parse error: expected integer literal after '+'\n"
|
"test:8: prefs parse error: expected integer literal after '+'\n"
|
||||||
"test:9: prefs parse error: expected ')' after pref value\n"
|
"test:9: prefs parse error: expected pref attribute after ','\n"
|
||||||
"test:11: prefs parse error: expected ';' after ')'\n"
|
"test:10: prefs parse error: expected ',' or ')' after pref value\n"
|
||||||
"test:12: prefs parse error: expected ';' after ')'\n"
|
"test:11: prefs parse error: expected ',' or ')' after pref attribute\n"
|
||||||
|
"test:13: prefs parse error: expected ';' after ')'\n"
|
||||||
|
"test:14: prefs parse error: expected ';' after ')'\n"
|
||||||
|
);
|
||||||
|
|
||||||
|
USER(R"(
|
||||||
|
pref("parse.error", true;
|
||||||
|
pref("int.ok", 1);
|
||||||
|
)",
|
||||||
|
"test:2: prefs parse error: expected ')' after pref value\n"
|
||||||
);
|
);
|
||||||
|
|
||||||
// Parse errors involving unexpected EOF.
|
// Parse errors involving unexpected EOF.
|
||||||
|
|
||||||
P(R"(
|
DEFAULT(R"(
|
||||||
pref)",
|
pref)",
|
||||||
"test:2: prefs parse error: expected '(' after pref specifier\n"
|
"test:2: prefs parse error: expected '(' after pref specifier\n"
|
||||||
);
|
);
|
||||||
|
|
||||||
P(R"(
|
DEFAULT(R"(
|
||||||
pref()",
|
pref()",
|
||||||
"test:2: prefs parse error: expected pref name after '('\n"
|
"test:2: prefs parse error: expected pref name after '('\n"
|
||||||
);
|
);
|
||||||
|
|
||||||
P(R"(
|
DEFAULT(R"(
|
||||||
pref("parse.error")",
|
pref("parse.error")",
|
||||||
"test:2: prefs parse error: expected ',' after pref name\n"
|
"test:2: prefs parse error: expected ',' after pref name\n"
|
||||||
);
|
);
|
||||||
|
|
||||||
P(R"(
|
DEFAULT(R"(
|
||||||
pref("parse.error",)",
|
pref("parse.error",)",
|
||||||
"test:2: prefs parse error: expected pref value after ','\n"
|
"test:2: prefs parse error: expected pref value after ','\n"
|
||||||
);
|
);
|
||||||
|
|
||||||
P(R"(
|
DEFAULT(R"(
|
||||||
pref("parse.error", -)",
|
pref("parse.error", -)",
|
||||||
"test:2: prefs parse error: expected integer literal after '-'\n"
|
"test:2: prefs parse error: expected integer literal after '-'\n"
|
||||||
);
|
);
|
||||||
|
|
||||||
P(R"(
|
DEFAULT(R"(
|
||||||
pref("parse.error", +)",
|
pref("parse.error", +)",
|
||||||
"test:2: prefs parse error: expected integer literal after '+'\n"
|
"test:2: prefs parse error: expected integer literal after '+'\n"
|
||||||
);
|
);
|
||||||
|
|
||||||
P(R"(
|
DEFAULT(R"(
|
||||||
|
pref("parse.error", true)",
|
||||||
|
"test:2: prefs parse error: expected ',' or ')' after pref value\n"
|
||||||
|
);
|
||||||
|
|
||||||
|
USER(R"(
|
||||||
pref("parse.error", true)",
|
pref("parse.error", true)",
|
||||||
"test:2: prefs parse error: expected ')' after pref value\n"
|
"test:2: prefs parse error: expected ')' after pref value\n"
|
||||||
);
|
);
|
||||||
|
|
||||||
P(R"(
|
DEFAULT(R"(
|
||||||
|
pref("parse.error", true,)",
|
||||||
|
"test:2: prefs parse error: expected pref attribute after ','\n"
|
||||||
|
);
|
||||||
|
|
||||||
|
DEFAULT(R"(
|
||||||
|
pref("parse.error", true, sticky)",
|
||||||
|
"test:2: prefs parse error: expected ',' or ')' after pref attribute\n"
|
||||||
|
);
|
||||||
|
|
||||||
|
DEFAULT(R"(
|
||||||
pref("parse.error", true))",
|
pref("parse.error", true))",
|
||||||
"test:2: prefs parse error: expected ';' after ')'\n"
|
"test:2: prefs parse error: expected ';' after ')'\n"
|
||||||
);
|
);
|
||||||
|
|
||||||
// This is something we saw in practice with the old parser, which allowed
|
// This is something we saw in practice with the old parser, which allowed
|
||||||
// repeated semicolons.
|
// repeated semicolons.
|
||||||
P(R"(
|
DEFAULT(R"(
|
||||||
pref("parse.error", true);;
|
pref("parse.error", true);;
|
||||||
pref("parse.error", true);;;
|
pref("parse.error", true, locked);;;
|
||||||
pref("parse.error", true);;;;
|
pref("parse.error", true, sticky, locked);;;;
|
||||||
pref("int.ok", 0);
|
pref("int.ok", 0);
|
||||||
)",
|
)",
|
||||||
"test:2: prefs parse error: expected pref specifier at start of pref definition\n"
|
"test:2: prefs parse error: expected pref specifier at start of pref definition\n"
|
||||||
|
@ -411,24 +446,24 @@ pref("int.ok", 0);
|
||||||
// the error is on line 4. (Note: these ones don't use raw string literals
|
// the error is on line 4. (Note: these ones don't use raw string literals
|
||||||
// because MSVC somehow swallows any \r that appears in them.)
|
// because MSVC somehow swallows any \r that appears in them.)
|
||||||
|
|
||||||
P("\n \r \r\n bad",
|
DEFAULT("\n \r \r\n bad",
|
||||||
"test:4: prefs parse error: unknown keyword\n"
|
"test:4: prefs parse error: unknown keyword\n"
|
||||||
);
|
);
|
||||||
|
|
||||||
P("#\n#\r#\r\n bad",
|
DEFAULT("#\n#\r#\r\n bad",
|
||||||
"test:4: prefs parse error: unknown keyword\n"
|
"test:4: prefs parse error: unknown keyword\n"
|
||||||
);
|
);
|
||||||
|
|
||||||
P("//\n//\r//\r\n bad",
|
DEFAULT("//\n//\r//\r\n bad",
|
||||||
"test:4: prefs parse error: unknown keyword\n"
|
"test:4: prefs parse error: unknown keyword\n"
|
||||||
);
|
);
|
||||||
|
|
||||||
P("/*\n \r \r\n*/ bad",
|
DEFAULT("/*\n \r \r\n*/ bad",
|
||||||
"test:4: prefs parse error: unknown keyword\n"
|
"test:4: prefs parse error: unknown keyword\n"
|
||||||
);
|
);
|
||||||
|
|
||||||
// Note: the escape sequences do *not* affect the line number.
|
// Note: the escape sequences do *not* affect the line number.
|
||||||
P("pref(\"foo\\n\n foo\\r\r foo\\r\\n\r\n foo\", bad);",
|
DEFAULT("pref(\"foo\\n\n foo\\r\r foo\\r\\n\r\n foo\", bad);",
|
||||||
"test:4: prefs parse error: unknown keyword\n"
|
"test:4: prefs parse error: unknown keyword\n"
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
// Note: this file tests only valid syntax. See
|
// Note: this file tests only valid syntax (of user pref files, not default
|
||||||
// modules/libpref/test/gtest/Parser.cpp for tests if invalid syntax.
|
// pref files). See modules/libpref/test/gtest/Parser.cpp for tests if invalid
|
||||||
|
// syntax.
|
||||||
|
|
||||||
#
|
#
|
||||||
# comment
|
# comment
|
||||||
|
@ -50,6 +51,10 @@ pref
|
||||||
pref("pref", true);
|
pref("pref", true);
|
||||||
sticky_pref("sticky_pref", true);
|
sticky_pref("sticky_pref", true);
|
||||||
user_pref("user_pref", true);
|
user_pref("user_pref", true);
|
||||||
|
pref("sticky_pref2", true, sticky);
|
||||||
|
pref("locked_pref", true, locked);
|
||||||
|
pref("locked_sticky_pref", true, locked, sticky,sticky,
|
||||||
|
locked, locked, locked);
|
||||||
|
|
||||||
pref("bool.true", true);
|
pref("bool.true", true);
|
||||||
pref("bool.false", false);
|
pref("bool.false", false);
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
pref("testPref.unlocked.int", 333);
|
||||||
|
pref("testPref.locked.int", 444, locked);
|
|
@ -0,0 +1,3 @@
|
||||||
|
// testPrefLocked.js defined this pref as a locked pref.
|
||||||
|
// Changing a locked pref has no effect.
|
||||||
|
user_pref("testPref.locked.int", 555);
|
|
@ -1,2 +1,2 @@
|
||||||
pref("testPref.unsticky.bool", true);
|
pref("testPref.unsticky.bool", true);
|
||||||
sticky_pref("testPref.sticky.bool", false);
|
pref("testPref.sticky.bool", false, sticky);
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
// testPrefSticky.js defined this pref as a sticky_pref(). Once a sticky
|
// testPrefSticky.js defined this pref as sticky. Once a sticky
|
||||||
// pref has been changed, it's written as a user_pref().
|
// pref has been changed, it's written as a user_pref().
|
||||||
// So this test file reflects that scenario.
|
// So this test file reflects that scenario.
|
||||||
// Note the default in testPrefSticky.js is also false.
|
// Note the default in testPrefSticky.js is also false.
|
||||||
|
|
|
@ -0,0 +1,45 @@
|
||||||
|
/* Any copyright is dedicated to the Public Domain.
|
||||||
|
* http://creativecommons.org/licenses/publicdomain/ */
|
||||||
|
|
||||||
|
// This file tests the `locked` attribute in default pref files.
|
||||||
|
|
||||||
|
Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||||
|
Components.utils.import("resource://gre/modules/Services.jsm");
|
||||||
|
|
||||||
|
const ps = Services.prefs;
|
||||||
|
|
||||||
|
add_test(function notChangedFromAPI() {
|
||||||
|
ps.resetPrefs();
|
||||||
|
ps.readDefaultPrefsFromFile(do_get_file("data/testPrefLocked.js"));
|
||||||
|
Assert.strictEqual(ps.getIntPref("testPref.unlocked.int"), 333);
|
||||||
|
Assert.strictEqual(ps.getIntPref("testPref.locked.int"), 444);
|
||||||
|
|
||||||
|
// Unlocked pref: can set the user value, which is used upon reading.
|
||||||
|
ps.setIntPref("testPref.unlocked.int", 334);
|
||||||
|
Assert.ok(ps.prefHasUserValue("testPref.unlocked.int"), "has a user value");
|
||||||
|
Assert.strictEqual(ps.getIntPref("testPref.unlocked.int"), 334);
|
||||||
|
|
||||||
|
// Locked pref: can set the user value, but the default value is used upon
|
||||||
|
// reading.
|
||||||
|
ps.setIntPref("testPref.locked.int", 445);
|
||||||
|
Assert.ok(ps.prefHasUserValue("testPref.locked.int"), "has a user value");
|
||||||
|
Assert.strictEqual(ps.getIntPref("testPref.locked.int"), 444);
|
||||||
|
|
||||||
|
// After unlocking, the user value is used.
|
||||||
|
ps.unlockPref("testPref.locked.int");
|
||||||
|
Assert.ok(ps.prefHasUserValue("testPref.locked.int"), "has a user value");
|
||||||
|
Assert.strictEqual(ps.getIntPref("testPref.locked.int"), 445);
|
||||||
|
|
||||||
|
run_next_test();
|
||||||
|
});
|
||||||
|
|
||||||
|
add_test(function notChangedFromUserPrefs() {
|
||||||
|
ps.resetPrefs();
|
||||||
|
ps.readDefaultPrefsFromFile(do_get_file("data/testPrefLocked.js"));
|
||||||
|
ps.readUserPrefsFromFile(do_get_file("data/testPrefLockedUser.js"));
|
||||||
|
|
||||||
|
Assert.strictEqual(ps.getIntPref("testPref.unlocked.int"), 333);
|
||||||
|
Assert.strictEqual(ps.getIntPref("testPref.locked.int"), 444);
|
||||||
|
|
||||||
|
run_next_test();
|
||||||
|
});
|
|
@ -10,7 +10,7 @@ function run_test() {
|
||||||
var prefs = ps.getBranch(null);
|
var prefs = ps.getBranch(null);
|
||||||
|
|
||||||
ps.resetPrefs();
|
ps.resetPrefs();
|
||||||
ps.readUserPrefsFromFile(do_get_file('data/testParser.js'));
|
ps.readDefaultPrefsFromFile(do_get_file('data/testParser.js'));
|
||||||
|
|
||||||
Assert.equal(ps.getBoolPref("comment1"), true);
|
Assert.equal(ps.getBoolPref("comment1"), true);
|
||||||
Assert.equal(ps.getBoolPref("comment2"), true);
|
Assert.equal(ps.getBoolPref("comment2"), true);
|
||||||
|
@ -19,6 +19,11 @@ function run_test() {
|
||||||
Assert.equal(ps.getBoolPref("pref"), true);
|
Assert.equal(ps.getBoolPref("pref"), true);
|
||||||
Assert.equal(ps.getBoolPref("sticky_pref"), true);
|
Assert.equal(ps.getBoolPref("sticky_pref"), true);
|
||||||
Assert.equal(ps.getBoolPref("user_pref"), true);
|
Assert.equal(ps.getBoolPref("user_pref"), true);
|
||||||
|
Assert.equal(ps.getBoolPref("sticky_pref2"), true);
|
||||||
|
Assert.equal(ps.getBoolPref("locked_pref"), true);
|
||||||
|
Assert.equal(ps.getBoolPref("locked_sticky_pref"), true);
|
||||||
|
Assert.equal(ps.prefIsLocked("locked_pref"), true);
|
||||||
|
Assert.equal(ps.prefIsLocked("locked_sticky_pref"), true);
|
||||||
|
|
||||||
Assert.equal(ps.getBoolPref("bool.true"), true);
|
Assert.equal(ps.getBoolPref("bool.true"), true);
|
||||||
Assert.equal(ps.getBoolPref("bool.false"), false);
|
Assert.equal(ps.getBoolPref("bool.false"), false);
|
||||||
|
|
|
@ -6,12 +6,17 @@ ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||||
|
|
||||||
const ps = Services.prefs;
|
const ps = Services.prefs;
|
||||||
|
|
||||||
// A little helper to reset the service and load some pref files
|
// A little helper to reset the service and load one pref file.
|
||||||
function resetAndLoad(filenames) {
|
function resetAndLoadDefaults() {
|
||||||
ps.resetPrefs();
|
ps.resetPrefs();
|
||||||
for (let filename of filenames) {
|
ps.readDefaultPrefsFromFile(do_get_file("data/testPrefSticky.js"));
|
||||||
ps.readUserPrefsFromFile(do_get_file(filename));
|
}
|
||||||
}
|
|
||||||
|
// A little helper to reset the service and load two pref files.
|
||||||
|
function resetAndLoadAll() {
|
||||||
|
ps.resetPrefs();
|
||||||
|
ps.readDefaultPrefsFromFile(do_get_file("data/testPrefSticky.js"));
|
||||||
|
ps.readUserPrefsFromFile(do_get_file("data/testPrefStickyUser.js"));
|
||||||
}
|
}
|
||||||
|
|
||||||
// A little helper that saves the current state to a file in the profile
|
// A little helper that saves the current state to a file in the profile
|
||||||
|
@ -39,7 +44,7 @@ function run_test() {
|
||||||
|
|
||||||
// A sticky pref should not be written if the value is unchanged.
|
// A sticky pref should not be written if the value is unchanged.
|
||||||
add_test(function notWrittenWhenUnchanged() {
|
add_test(function notWrittenWhenUnchanged() {
|
||||||
resetAndLoad(["data/testPrefSticky.js"]);
|
resetAndLoadDefaults();
|
||||||
Assert.strictEqual(ps.getBoolPref("testPref.unsticky.bool"), true);
|
Assert.strictEqual(ps.getBoolPref("testPref.unsticky.bool"), true);
|
||||||
Assert.strictEqual(ps.getBoolPref("testPref.sticky.bool"), false);
|
Assert.strictEqual(ps.getBoolPref("testPref.sticky.bool"), false);
|
||||||
|
|
||||||
|
@ -55,13 +60,13 @@ add_test(function notWrittenWhenUnchanged() {
|
||||||
run_next_test();
|
run_next_test();
|
||||||
});
|
});
|
||||||
|
|
||||||
// Loading a sticky_pref then a user_pref for the same pref means it should
|
// Loading a sticky `pref` then a `user_pref` for the same pref means it should
|
||||||
// always be written.
|
// always be written.
|
||||||
add_test(function writtenOnceLoadedWithoutChange() {
|
add_test(function writtenOnceLoadedWithoutChange() {
|
||||||
// Load the same pref file *as well as* a pref file that has a user_pref for
|
// 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
|
// our sticky with the default value. It should be re-written without us
|
||||||
// touching it.
|
// touching it.
|
||||||
resetAndLoad(["data/testPrefSticky.js", "data/testPrefStickyUser.js"]);
|
resetAndLoadAll();
|
||||||
// reset and re-read what we just wrote - it should be written.
|
// reset and re-read what we just wrote - it should be written.
|
||||||
saveAndReload();
|
saveAndReload();
|
||||||
Assert.strictEqual(ps.getBoolPref("testPref.sticky.bool"), false,
|
Assert.strictEqual(ps.getBoolPref("testPref.sticky.bool"), false,
|
||||||
|
@ -73,7 +78,7 @@ add_test(function writtenOnceLoadedWithoutChange() {
|
||||||
add_test(function writtenOnceLoadedWithChangeNonDefault() {
|
add_test(function writtenOnceLoadedWithChangeNonDefault() {
|
||||||
// Load the same pref file *as well as* a pref file that has a user_pref for
|
// 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.
|
// our sticky - then change the pref. It should be written.
|
||||||
resetAndLoad(["data/testPrefSticky.js", "data/testPrefStickyUser.js"]);
|
resetAndLoadAll();
|
||||||
// Set a new val and check we wrote it.
|
// Set a new val and check we wrote it.
|
||||||
ps.setBoolPref("testPref.sticky.bool", false);
|
ps.setBoolPref("testPref.sticky.bool", false);
|
||||||
saveAndReload();
|
saveAndReload();
|
||||||
|
@ -86,7 +91,7 @@ add_test(function writtenOnceLoadedWithChangeNonDefault() {
|
||||||
add_test(function writtenOnceLoadedWithChangeNonDefault() {
|
add_test(function writtenOnceLoadedWithChangeNonDefault() {
|
||||||
// Load the same pref file *as well as* a pref file that has a user_pref for
|
// 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.
|
// our sticky - then change the pref. It should be written.
|
||||||
resetAndLoad(["data/testPrefSticky.js", "data/testPrefStickyUser.js"]);
|
resetAndLoadAll();
|
||||||
// Set a new val and check we wrote it.
|
// Set a new val and check we wrote it.
|
||||||
ps.setBoolPref("testPref.sticky.bool", true);
|
ps.setBoolPref("testPref.sticky.bool", true);
|
||||||
saveAndReload();
|
saveAndReload();
|
||||||
|
@ -102,7 +107,7 @@ add_test(function writtenOnceLoadedWithChangeNonDefault() {
|
||||||
// the pref had never changed.)
|
// the pref had never changed.)
|
||||||
add_test(function hasUserValue() {
|
add_test(function hasUserValue() {
|
||||||
// sticky pref without user value.
|
// sticky pref without user value.
|
||||||
resetAndLoad(["data/testPrefSticky.js"]);
|
resetAndLoadDefaults();
|
||||||
Assert.strictEqual(ps.getBoolPref("testPref.sticky.bool"), false);
|
Assert.strictEqual(ps.getBoolPref("testPref.sticky.bool"), false);
|
||||||
Assert.ok(!ps.prefHasUserValue("testPref.sticky.bool"),
|
Assert.ok(!ps.prefHasUserValue("testPref.sticky.bool"),
|
||||||
"should not initially reflect a user value");
|
"should not initially reflect a user value");
|
||||||
|
@ -121,7 +126,7 @@ add_test(function hasUserValue() {
|
||||||
ps.setBoolPref("testPref.sticky.bool", false, "expected default");
|
ps.setBoolPref("testPref.sticky.bool", false, "expected default");
|
||||||
|
|
||||||
// And make sure the pref immediately reflects a user value after load.
|
// And make sure the pref immediately reflects a user value after load.
|
||||||
resetAndLoad(["data/testPrefSticky.js", "data/testPrefStickyUser.js"]);
|
resetAndLoadAll();
|
||||||
Assert.strictEqual(ps.getBoolPref("testPref.sticky.bool"), false);
|
Assert.strictEqual(ps.getBoolPref("testPref.sticky.bool"), false);
|
||||||
Assert.ok(ps.prefHasUserValue("testPref.sticky.bool"),
|
Assert.ok(ps.prefHasUserValue("testPref.sticky.bool"),
|
||||||
"should have a user value when loaded value is the default");
|
"should have a user value when loaded value is the default");
|
||||||
|
@ -132,7 +137,7 @@ add_test(function hasUserValue() {
|
||||||
add_test(function clearUserPref() {
|
add_test(function clearUserPref() {
|
||||||
// load things such that we have a sticky value which is the same as the
|
// load things such that we have a sticky value which is the same as the
|
||||||
// default.
|
// default.
|
||||||
resetAndLoad(["data/testPrefSticky.js", "data/testPrefStickyUser.js"]);
|
resetAndLoadAll();
|
||||||
ps.clearUserPref("testPref.sticky.bool");
|
ps.clearUserPref("testPref.sticky.bool");
|
||||||
|
|
||||||
// Once we save prefs the sticky pref should no longer be written.
|
// Once we save prefs the sticky pref should no longer be written.
|
||||||
|
@ -153,7 +158,7 @@ add_test(function clearUserPref() {
|
||||||
// even if the value has not)
|
// even if the value has not)
|
||||||
add_test(function observerFires() {
|
add_test(function observerFires() {
|
||||||
// load things so there's no sticky value.
|
// load things so there's no sticky value.
|
||||||
resetAndLoad(["data/testPrefSticky.js"]);
|
resetAndLoadDefaults();
|
||||||
|
|
||||||
function observe(subject, topic, data) {
|
function observe(subject, topic, data) {
|
||||||
Assert.equal(data, "testPref.sticky.bool");
|
Assert.equal(data, "testPref.sticky.bool");
|
||||||
|
|
|
@ -11,6 +11,8 @@ support-files =
|
||||||
[test_bug790374.js]
|
[test_bug790374.js]
|
||||||
[test_stickyprefs.js]
|
[test_stickyprefs.js]
|
||||||
support-files = data/testPrefSticky.js data/testPrefStickyUser.js
|
support-files = data/testPrefSticky.js data/testPrefStickyUser.js
|
||||||
|
[test_locked_file_prefs.js]
|
||||||
|
support-files = data/testPrefLocked.js data/testPrefLockedUser.js
|
||||||
[test_changeType.js]
|
[test_changeType.js]
|
||||||
[test_defaultValues.js]
|
[test_defaultValues.js]
|
||||||
[test_dirtyPrefs.js]
|
[test_dirtyPrefs.js]
|
||||||
|
|
|
@ -25,7 +25,7 @@ function makePersona(id) {
|
||||||
add_task(async function run_test() {
|
add_task(async function run_test() {
|
||||||
_("Test fixtures.");
|
_("Test fixtures.");
|
||||||
// read our custom prefs file before doing anything.
|
// read our custom prefs file before doing anything.
|
||||||
Services.prefs.readUserPrefsFromFile(do_get_file("prefs_test_prefs_store.js"));
|
Services.prefs.readDefaultPrefsFromFile(do_get_file("prefs_test_prefs_store.js"));
|
||||||
|
|
||||||
let engine = Service.engineManager.get("prefs");
|
let engine = Service.engineManager.get("prefs");
|
||||||
let store = engine._store;
|
let store = engine._store;
|
||||||
|
|
|
@ -5099,12 +5099,14 @@
|
||||||
${ElevateUAC}
|
${ElevateUAC}
|
||||||
${EndIf}
|
${EndIf}
|
||||||
|
|
||||||
ReadINIStr $R8 $R7 "Install" "OptionalExtensions"
|
!ifdef MOZ_OPTIONAL_EXTENSIONS
|
||||||
${If} $R8 == "false"
|
ReadINIStr $R8 $R7 "Install" "OptionalExtensions"
|
||||||
StrCpy $InstallOptionalExtensions "0"
|
${If} $R8 == "false"
|
||||||
${Else}
|
StrCpy $InstallOptionalExtensions "0"
|
||||||
StrCpy $InstallOptionalExtensions "1"
|
${Else}
|
||||||
${EndIf}
|
StrCpy $InstallOptionalExtensions "1"
|
||||||
|
${EndIf}
|
||||||
|
!endif
|
||||||
|
|
||||||
!ifndef NO_STARTMENU_DIR
|
!ifndef NO_STARTMENU_DIR
|
||||||
ReadINIStr $R8 $R7 "Install" "StartMenuDirectoryName"
|
ReadINIStr $R8 $R7 "Install" "StartMenuDirectoryName"
|
||||||
|
|
|
@ -675,7 +675,6 @@ int main()
|
||||||
TestDetour("user32.dll", "CreateWindowExW") &&
|
TestDetour("user32.dll", "CreateWindowExW") &&
|
||||||
TestHook(TestInSendMessageEx, "user32.dll", "InSendMessageEx") &&
|
TestHook(TestInSendMessageEx, "user32.dll", "InSendMessageEx") &&
|
||||||
TestHook(TestImmGetContext, "imm32.dll", "ImmGetContext") &&
|
TestHook(TestImmGetContext, "imm32.dll", "ImmGetContext") &&
|
||||||
// TestHook("imm32.dll", "ImmReleaseContext") && // see Bug 1316415
|
|
||||||
TestHook(TestImmGetCompositionStringW, "imm32.dll", "ImmGetCompositionStringW") &&
|
TestHook(TestImmGetCompositionStringW, "imm32.dll", "ImmGetCompositionStringW") &&
|
||||||
TestHook(TestImmSetCandidateWindow, "imm32.dll", "ImmSetCandidateWindow") &&
|
TestHook(TestImmSetCandidateWindow, "imm32.dll", "ImmSetCandidateWindow") &&
|
||||||
TestHook(TestImmNotifyIME, "imm32.dll", "ImmNotifyIME") &&
|
TestHook(TestImmNotifyIME, "imm32.dll", "ImmNotifyIME") &&
|
||||||
|
|
|
@ -38,12 +38,6 @@ public:
|
||||||
return Equals(aString.BeginReading(), aString.Length());
|
return Equals(aString.BeginReading(), aString.Length());
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetKind(AtomKind aKind)
|
|
||||||
{
|
|
||||||
mKind = static_cast<uint32_t>(aKind);
|
|
||||||
MOZ_ASSERT(Kind() == aKind);
|
|
||||||
}
|
|
||||||
|
|
||||||
AtomKind Kind() const { return static_cast<AtomKind>(mKind); }
|
AtomKind Kind() const { return static_cast<AtomKind>(mKind); }
|
||||||
|
|
||||||
bool IsDynamicAtom() const { return Kind() == AtomKind::DynamicAtom; }
|
bool IsDynamicAtom() const { return Kind() == AtomKind::DynamicAtom; }
|
||||||
|
@ -57,12 +51,13 @@ public:
|
||||||
void ToString(nsAString& aString) const;
|
void ToString(nsAString& aString) const;
|
||||||
void ToUTF8String(nsACString& aString) const;
|
void ToUTF8String(nsACString& aString) const;
|
||||||
|
|
||||||
// This is only valid for dynamic atoms.
|
// This is not valid for static atoms. The caller must *not* mutate the
|
||||||
|
// string buffer, otherwise all hell will break loose.
|
||||||
nsStringBuffer* GetStringBuffer() const
|
nsStringBuffer* GetStringBuffer() const
|
||||||
{
|
{
|
||||||
// See the comment on |mString|'s declaration.
|
// See the comment on |mString|'s declaration.
|
||||||
MOZ_ASSERT(IsDynamicAtom());
|
MOZ_ASSERT(IsDynamicAtom() || IsHTML5Atom());
|
||||||
return nsStringBuffer::FromData(mString);
|
return nsStringBuffer::FromData(const_cast<char16_t*>(mString));
|
||||||
}
|
}
|
||||||
|
|
||||||
// A hashcode that is better distributed than the actual atom pointer, for
|
// A hashcode that is better distributed than the actual atom pointer, for
|
||||||
|
@ -88,23 +83,23 @@ private:
|
||||||
friend class nsAtomSubTable;
|
friend class nsAtomSubTable;
|
||||||
friend class nsHtml5AtomEntry;
|
friend class nsHtml5AtomEntry;
|
||||||
|
|
||||||
// Dynamic atom construction is done by |friend|s.
|
protected:
|
||||||
|
// Used by nsDynamicAtom and directly (by nsHtml5AtomEntry) for HTML5 atoms.
|
||||||
nsAtom(AtomKind aKind, const nsAString& aString, uint32_t aHash);
|
nsAtom(AtomKind aKind, const nsAString& aString, uint32_t aHash);
|
||||||
|
|
||||||
protected:
|
// Used by nsStaticAtom.
|
||||||
nsAtom(const char16_t* aString, uint32_t aLength, uint32_t aHash);
|
nsAtom(const char16_t* aString, uint32_t aLength, uint32_t aHash);
|
||||||
|
|
||||||
~nsAtom();
|
~nsAtom();
|
||||||
|
|
||||||
mozilla::ThreadSafeAutoRefCnt mRefCnt;
|
const uint32_t mLength:30;
|
||||||
uint32_t mLength: 30;
|
const uint32_t mKind:2; // nsAtom::AtomKind
|
||||||
uint32_t mKind: 2; // nsAtom::AtomKind
|
const uint32_t mHash;
|
||||||
uint32_t mHash;
|
|
||||||
// WARNING! For static atoms, this is a pointer to a static char buffer. For
|
// WARNING! For static atoms, this is a pointer to a static char buffer. For
|
||||||
// non-static atoms it points to the chars in an nsStringBuffer. This means
|
// non-static atoms it points to the chars in an nsStringBuffer. This means
|
||||||
// that nsStringBuffer::FromData(mString) calls are only valid for non-static
|
// that nsStringBuffer::FromData(mString) calls are only valid for non-static
|
||||||
// atoms.
|
// atoms.
|
||||||
char16_t* mString;
|
const char16_t* const mString;
|
||||||
};
|
};
|
||||||
|
|
||||||
// A trivial subclass of nsAtom that can be used for known static atoms. The
|
// A trivial subclass of nsAtom that can be used for known static atoms. The
|
||||||
|
@ -118,7 +113,7 @@ class nsStaticAtom : public nsAtom
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
// These are deleted so it's impossible to RefPtr<nsStaticAtom>. Raw
|
// These are deleted so it's impossible to RefPtr<nsStaticAtom>. Raw
|
||||||
// nsStaticAtom atoms should be used instead.
|
// nsStaticAtom pointers should be used instead.
|
||||||
MozExternalRefCountType AddRef() = delete;
|
MozExternalRefCountType AddRef() = delete;
|
||||||
MozExternalRefCountType Release() = delete;
|
MozExternalRefCountType Release() = delete;
|
||||||
|
|
||||||
|
|
|
@ -64,39 +64,75 @@ enum class GCKind {
|
||||||
// See nsAtom::AddRef() and nsAtom::Release().
|
// See nsAtom::AddRef() and nsAtom::Release().
|
||||||
static Atomic<int32_t, ReleaseAcquire> gUnusedAtomCount(0);
|
static Atomic<int32_t, ReleaseAcquire> gUnusedAtomCount(0);
|
||||||
|
|
||||||
// This constructor is for dynamic atoms and HTML5 atoms.
|
// Dynamic atoms need a ref count; this class adds that to nsAtom.
|
||||||
nsAtom::nsAtom(AtomKind aKind, const nsAString& aString, uint32_t aHash)
|
class nsDynamicAtom : public nsAtom
|
||||||
: mRefCnt(1)
|
|
||||||
, mLength(aString.Length())
|
|
||||||
, mKind(static_cast<uint32_t>(aKind))
|
|
||||||
, mHash(aHash)
|
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(aKind == AtomKind::DynamicAtom || aKind == AtomKind::HTML5Atom);
|
public:
|
||||||
RefPtr<nsStringBuffer> buf = nsStringBuffer::FromString(aString);
|
// We can't use NS_INLINE_DECL_THREADSAFE_REFCOUNTING because the refcounting
|
||||||
if (buf) {
|
// of this type is special.
|
||||||
mString = static_cast<char16_t*>(buf->Data());
|
MozExternalRefCountType AddRef();
|
||||||
} else {
|
MozExternalRefCountType Release();
|
||||||
const size_t size = (mLength + 1) * sizeof(char16_t);
|
|
||||||
buf = nsStringBuffer::Alloc(size);
|
static nsDynamicAtom* As(nsAtom* aAtom)
|
||||||
if (MOZ_UNLIKELY(!buf)) {
|
{
|
||||||
// We OOM because atom allocations should be small and it's hard to
|
MOZ_ASSERT(aAtom->IsDynamicAtom());
|
||||||
// handle them more gracefully in a constructor.
|
return static_cast<nsDynamicAtom*>(aAtom);
|
||||||
NS_ABORT_OOM(size);
|
|
||||||
}
|
|
||||||
mString = static_cast<char16_t*>(buf->Data());
|
|
||||||
CopyUnicodeTo(aString, 0, mString, mLength);
|
|
||||||
mString[mLength] = char16_t(0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
MOZ_ASSERT_IF(IsDynamicAtom(), mHash == HashString(mString, mLength));
|
private:
|
||||||
|
friend class nsAtomTable;
|
||||||
|
friend class nsAtomSubTable;
|
||||||
|
|
||||||
|
// Construction is done by |friend|s.
|
||||||
|
nsDynamicAtom(const nsAString& aString, uint32_t aHash)
|
||||||
|
: nsAtom(AtomKind::DynamicAtom, aString, aHash)
|
||||||
|
, mRefCnt(1)
|
||||||
|
{}
|
||||||
|
|
||||||
|
mozilla::ThreadSafeAutoRefCnt mRefCnt;
|
||||||
|
};
|
||||||
|
|
||||||
|
static char16_t*
|
||||||
|
FromStringBuffer(const nsAString& aString)
|
||||||
|
{
|
||||||
|
char16_t* str;
|
||||||
|
size_t length = aString.Length();
|
||||||
|
RefPtr<nsStringBuffer> buf = nsStringBuffer::FromString(aString);
|
||||||
|
if (buf) {
|
||||||
|
str = static_cast<char16_t*>(buf->Data());
|
||||||
|
} else {
|
||||||
|
const size_t size = (length + 1) * sizeof(char16_t);
|
||||||
|
buf = nsStringBuffer::Alloc(size);
|
||||||
|
if (MOZ_UNLIKELY(!buf)) {
|
||||||
|
NS_ABORT_OOM(size); // OOM because atom allocations should be small.
|
||||||
|
}
|
||||||
|
str = static_cast<char16_t*>(buf->Data());
|
||||||
|
CopyUnicodeTo(aString, 0, str, length);
|
||||||
|
str[length] = char16_t(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
MOZ_ASSERT(buf && buf->StorageSize() >= (length + 1) * sizeof(char16_t),
|
||||||
|
"enough storage");
|
||||||
|
|
||||||
|
// Take ownership of the string buffer.
|
||||||
|
mozilla::Unused << buf.forget();
|
||||||
|
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
// This constructor is for dynamic atoms and HTML5 atoms.
|
||||||
|
nsAtom::nsAtom(AtomKind aKind, const nsAString& aString, uint32_t aHash)
|
||||||
|
: mLength(aString.Length())
|
||||||
|
, mKind(static_cast<uint32_t>(aKind))
|
||||||
|
, mHash(aHash)
|
||||||
|
, mString(FromStringBuffer(aString))
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(aKind == AtomKind::DynamicAtom || aKind == AtomKind::HTML5Atom);
|
||||||
|
|
||||||
|
MOZ_ASSERT_IF(!IsHTML5Atom(), mHash == HashString(mString, mLength));
|
||||||
|
|
||||||
MOZ_ASSERT(mString[mLength] == char16_t(0), "null terminated");
|
MOZ_ASSERT(mString[mLength] == char16_t(0), "null terminated");
|
||||||
MOZ_ASSERT(buf && buf->StorageSize() >= (mLength + 1) * sizeof(char16_t),
|
|
||||||
"enough storage");
|
|
||||||
MOZ_ASSERT(Equals(aString), "correct data");
|
MOZ_ASSERT(Equals(aString), "correct data");
|
||||||
|
|
||||||
// Take ownership of buffer
|
|
||||||
mozilla::Unused << buf.forget();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// This constructor is for static atoms.
|
// This constructor is for static atoms.
|
||||||
|
@ -116,7 +152,7 @@ nsAtom::~nsAtom()
|
||||||
{
|
{
|
||||||
if (!IsStaticAtom()) {
|
if (!IsStaticAtom()) {
|
||||||
MOZ_ASSERT(IsDynamicAtom() || IsHTML5Atom());
|
MOZ_ASSERT(IsDynamicAtom() || IsHTML5Atom());
|
||||||
nsStringBuffer::FromData(mString)->Release();
|
GetStringBuffer()->Release();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -130,7 +166,7 @@ nsAtom::ToString(nsAString& aString) const
|
||||||
// which is what's important.
|
// which is what's important.
|
||||||
aString.AssignLiteral(mString, mLength);
|
aString.AssignLiteral(mString, mLength);
|
||||||
} else {
|
} else {
|
||||||
nsStringBuffer::FromData(mString)->ToString(mLength, aString);
|
GetStringBuffer()->ToString(mLength, aString);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -155,8 +191,7 @@ nsAtom::AddSizeOfIncludingThis(MallocSizeOf aMallocSizeOf, AtomsSizes& aSizes)
|
||||||
} else {
|
} else {
|
||||||
aSizes.mDynamicAtomObjects += thisSize;
|
aSizes.mDynamicAtomObjects += thisSize;
|
||||||
aSizes.mDynamicUnsharedBuffers +=
|
aSizes.mDynamicUnsharedBuffers +=
|
||||||
nsStringBuffer::FromData(mString)->SizeOfIncludingThisIfUnshared(
|
GetStringBuffer()->SizeOfIncludingThisIfUnshared(aMallocSizeOf);
|
||||||
aMallocSizeOf);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -474,7 +509,8 @@ nsAtomSubTable::GCLocked(GCKind aKind)
|
||||||
}
|
}
|
||||||
|
|
||||||
nsAtom* atom = entry->mAtom;
|
nsAtom* atom = entry->mAtom;
|
||||||
if (atom->mRefCnt == 0) {
|
MOZ_ASSERT(!atom->IsHTML5Atom());
|
||||||
|
if (atom->IsDynamicAtom() && nsDynamicAtom::As(atom)->mRefCnt == 0) {
|
||||||
i.Remove();
|
i.Remove();
|
||||||
delete atom;
|
delete atom;
|
||||||
++removedCount;
|
++removedCount;
|
||||||
|
@ -516,15 +552,9 @@ GCAtomTable()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
MozExternalRefCountType
|
MOZ_ALWAYS_INLINE MozExternalRefCountType
|
||||||
nsAtom::AddRef()
|
nsDynamicAtom::AddRef()
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(!IsHTML5Atom(), "Attempt to AddRef an HTML5 atom");
|
|
||||||
if (!IsDynamicAtom()) {
|
|
||||||
MOZ_ASSERT(IsStaticAtom());
|
|
||||||
return 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
MOZ_ASSERT(int32_t(mRefCnt) >= 0, "illegal refcnt");
|
MOZ_ASSERT(int32_t(mRefCnt) >= 0, "illegal refcnt");
|
||||||
nsrefcnt count = ++mRefCnt;
|
nsrefcnt count = ++mRefCnt;
|
||||||
if (count == 1) {
|
if (count == 1) {
|
||||||
|
@ -533,15 +563,9 @@ nsAtom::AddRef()
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
MozExternalRefCountType
|
MOZ_ALWAYS_INLINE MozExternalRefCountType
|
||||||
nsAtom::Release()
|
nsDynamicAtom::Release()
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(!IsHTML5Atom(), "Attempt to Release an HTML5 atom");
|
|
||||||
if (!IsDynamicAtom()) {
|
|
||||||
MOZ_ASSERT(IsStaticAtom());
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
// We set a lower GC threshold for atoms in debug builds so that we exercise
|
// We set a lower GC threshold for atoms in debug builds so that we exercise
|
||||||
// the GC machinery more often.
|
// the GC machinery more often.
|
||||||
|
@ -561,6 +585,22 @@ nsAtom::Release()
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MozExternalRefCountType
|
||||||
|
nsAtom::AddRef()
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(!IsHTML5Atom(), "Attempt to AddRef an HTML5 atom");
|
||||||
|
|
||||||
|
return IsStaticAtom() ? 2 : nsDynamicAtom::As(this)->AddRef();
|
||||||
|
}
|
||||||
|
|
||||||
|
MozExternalRefCountType
|
||||||
|
nsAtom::Release()
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(!IsHTML5Atom(), "Attempt to Release an HTML5 atom");
|
||||||
|
|
||||||
|
return IsStaticAtom() ? 1 : nsDynamicAtom::As(this)->Release();
|
||||||
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------
|
//----------------------------------------------------------------------
|
||||||
|
|
||||||
// Have the static atoms been inserted into the table?
|
// Have the static atoms been inserted into the table?
|
||||||
|
@ -706,8 +746,7 @@ nsAtomTable::Atomize(const nsACString& aUTF8String)
|
||||||
// Actually, now there is, sort of: ForgetSharedBuffer.
|
// Actually, now there is, sort of: ForgetSharedBuffer.
|
||||||
nsString str;
|
nsString str;
|
||||||
CopyUTF8toUTF16(aUTF8String, str);
|
CopyUTF8toUTF16(aUTF8String, str);
|
||||||
RefPtr<nsAtom> atom =
|
RefPtr<nsAtom> atom = dont_AddRef(new nsDynamicAtom(str, hash));
|
||||||
dont_AddRef(new nsAtom(nsAtom::AtomKind::DynamicAtom, str, hash));
|
|
||||||
|
|
||||||
he->mAtom = atom;
|
he->mAtom = atom;
|
||||||
|
|
||||||
|
@ -743,8 +782,7 @@ nsAtomTable::Atomize(const nsAString& aUTF16String)
|
||||||
return atom.forget();
|
return atom.forget();
|
||||||
}
|
}
|
||||||
|
|
||||||
RefPtr<nsAtom> atom =
|
RefPtr<nsAtom> atom = dont_AddRef(new nsDynamicAtom(aUTF16String, hash));
|
||||||
dont_AddRef(new nsAtom(nsAtom::AtomKind::DynamicAtom, aUTF16String, hash));
|
|
||||||
he->mAtom = atom;
|
he->mAtom = atom;
|
||||||
|
|
||||||
return atom.forget();
|
return atom.forget();
|
||||||
|
@ -783,8 +821,7 @@ nsAtomTable::AtomizeMainThread(const nsAString& aUTF16String)
|
||||||
if (he->mAtom) {
|
if (he->mAtom) {
|
||||||
retVal = he->mAtom;
|
retVal = he->mAtom;
|
||||||
} else {
|
} else {
|
||||||
RefPtr<nsAtom> newAtom = dont_AddRef(
|
RefPtr<nsAtom> newAtom = dont_AddRef(new nsDynamicAtom(aUTF16String, hash));
|
||||||
new nsAtom(nsAtom::AtomKind::DynamicAtom, aUTF16String, hash));
|
|
||||||
he->mAtom = newAtom;
|
he->mAtom = newAtom;
|
||||||
retVal = newAtom.forget();
|
retVal = newAtom.forget();
|
||||||
}
|
}
|
||||||
|
|
Загрузка…
Ссылка в новой задаче