Bug 1249157: prefapi enums into class enums, explicit conversion, cleanup. r=bsmedberg draft
authorMilan Sreckovic <milan@mozilla.com>
Thu, 18 Feb 2016 13:27:06 -0500
changeset 331879 cbdaea69100559893e8386c3618a5594ff38433d
parent 331857 fcd35e10fa17d9fd11d92be48ae9698c2a900f1c
child 514497 593f8db42667cf8ddbbcfa73412d32e1d41d1b71
push id11111
push usermsreckovic@mozilla.com
push dateThu, 18 Feb 2016 18:29:14 +0000
reviewersbsmedberg
bugs1249157
milestone47.0a1
Bug 1249157: prefapi enums into class enums, explicit conversion, cleanup. r=bsmedberg MozReview-Commit-ID: nvvOD8ajV4
modules/libpref/Preferences.cpp
modules/libpref/nsPrefBranch.cpp
modules/libpref/prefapi.cpp
modules/libpref/prefapi.h
modules/libpref/prefread.cpp
modules/libpref/prefread.h
--- a/modules/libpref/Preferences.cpp
+++ b/modules/libpref/Preferences.cpp
@@ -1310,17 +1310,17 @@ static nsresult pref_InitInitialObjects(
   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) == PREF_INVALID) {
+  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
--- a/modules/libpref/nsPrefBranch.cpp
+++ b/modules/libpref/nsPrefBranch.cpp
@@ -122,17 +122,31 @@ NS_IMETHODIMP nsPrefBranch::GetRoot(char
   *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);
-  *_retval = PREF_GetPrefType(pref);
+  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);
--- a/modules/libpref/prefapi.cpp
+++ b/modules/libpref/prefapi.cpp
@@ -35,17 +35,17 @@
 #include "prlink.h"
 
 using namespace mozilla;
 
 static void
 clearPrefEntry(PLDHashTable *table, PLDHashEntryHdr *entry)
 {
     PrefHashEntry *pref = static_cast<PrefHashEntry *>(entry);
-    if (pref->flags & PREF_STRING)
+    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
@@ -112,23 +112,17 @@ static char *ArenaStrDup(const char* str
     PL_ARENA_ALLOCATE(mem, aArena, len+1);
     if (mem)
         memcpy(mem, str, len+1);
     return static_cast<char*>(mem);
 }
 
 /*---------------------------------------------------------------------------*/
 
-#define PREF_IS_LOCKED(pref)            ((pref)->flags & PREF_LOCKED)
-#define PREF_HAS_DEFAULT_VALUE(pref)    ((pref)->flags & PREF_HAS_DEFAULT)
-#define PREF_HAS_USER_VALUE(pref)       ((pref)->flags & PREF_USERSET)
-#define PREF_TYPE(pref)                 (PrefType)((pref)->flags & PREF_VALUETYPE_MASK)
-
 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;
@@ -244,35 +238,35 @@ PREF_SetCharPref(const char *pref_name, 
 {
     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, PREF_STRING, set_default ? kPrefSetDefault : 0);
+    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, PREF_INT, set_default ? kPrefSetDefault : 0);
+    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, PREF_BOOL, set_default ? kPrefSetDefault : 0);
+    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);
@@ -330,38 +324,38 @@ pref_savePrefs(PLDHashTable* aTable)
 
         nsAutoCString prefValue;
         nsAutoCString prefPrefix;
         prefPrefix.AssignLiteral("user_pref(\"");
 
         // where we're getting our pref from
         PrefValue* sourcePref;
 
-        if (PREF_HAS_USER_VALUE(pref) &&
+        if (pref->prefFlags.HasUserValue() &&
             (pref_ValueChanged(pref->defaultPref,
                                pref->userPref,
-                               (PrefType) PREF_TYPE(pref)) ||
-             !(pref->flags & PREF_HAS_DEFAULT) ||
-             pref->flags & PREF_STICKY_DEFAULT)) {
+                               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->flags & PREF_STRING) {
+        if (pref->prefFlags.IsTypeString()) {
             prefValue = '\"';
             str_escape(sourcePref->stringVal, prefValue);
             prefValue += '\"';
 
-        } else if (pref->flags & PREF_INT) {
+        } else if (pref->prefFlags.IsTypeInt()) {
             prefValue.AppendInt(sourcePref->intVal);
 
-        } else if (pref->flags & PREF_BOOL) {
+        } else if (pref->prefFlags.IsTypeBool()) {
             prefValue = (sourcePref->boolVal) ? "true" : "false";
         }
 
         nsAutoCString prefName;
         str_escape(pref->key, prefName);
 
         savedPrefs[j++] = ToNewCString(prefPrefix +
                                        prefName +
@@ -384,41 +378,41 @@ GetPrefValueFromEntry(PrefHashEntry *aHa
         aPref->userValue() = dom::PrefValue();
         settingValue = &aPref->userValue().get_PrefValue();
     } else {
         value = &aHashEntry->defaultPref;
         aPref->defaultValue() = dom::PrefValue();
         settingValue = &aPref->defaultValue().get_PrefValue();
     }
 
-    switch (aHashEntry->flags & PREF_VALUETYPE_MASK) {
-    case PREF_STRING:
+    switch (aHashEntry->prefFlags.GetPrefType()) {
+      case PrefType::String:
         *settingValue = nsDependentCString(value->stringVal);
         return;
-    case PREF_INT:
+      case PrefType::Int:
         *settingValue = value->intVal;
         return;
-    case PREF_BOOL:
+      case PrefType::Bool:
         *settingValue = !!value->boolVal;
         return;
     default:
         MOZ_CRASH();
     }
 }
 
 void
 pref_GetPrefFromEntry(PrefHashEntry *aHashEntry, dom::PrefSetting* aPref)
 {
     aPref->name() = aHashEntry->key;
-    if (PREF_HAS_DEFAULT_VALUE(aHashEntry)) {
+    if (aHashEntry->prefFlags.HasDefault()) {
         GetPrefValueFromEntry(aHashEntry, aPref, DEFAULT_VALUE);
     } else {
         aPref->defaultValue() = null_t();
     }
-    if (PREF_HAS_USER_VALUE(aHashEntry)) {
+    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() ==
@@ -446,92 +440,84 @@ pref_CompareStrings(const void *v1, cons
 }
 
 bool PREF_HasUserPref(const char *pref_name)
 {
     if (!gHashTable)
         return false;
 
     PrefHashEntry *pref = pref_HashTableLookup(pref_name);
-    if (!pref) return false;
-
-    /* convert PREF_HAS_USER_VALUE to bool */
-    return (PREF_HAS_USER_VALUE(pref) != 0);
-
+    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->flags & PREF_STRING))
-    {
-        if (get_default || PREF_IS_LOCKED(pref) || !PREF_HAS_USER_VALUE(pref))
+    if (pref && (pref->prefFlags.IsTypeString())) {
+        if (get_default || pref->prefFlags.IsLocked() || !pref->prefFlags.HasUserValue()) {
             stringVal = pref->defaultPref.stringVal;
-        else
+        } 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->flags & PREF_INT))
-    {
-        if (get_default || PREF_IS_LOCKED(pref) || !PREF_HAS_USER_VALUE(pref))
-        {
+    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->flags & PREF_HAS_DEFAULT))
+            if (!pref->prefFlags.HasDefault()) {
                 return NS_ERROR_UNEXPECTED;
+            }
             *return_int = tempInt;
+        } else {
+            *return_int = pref->userPref.intVal;
         }
-        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->flags & PREF_BOOL))
-    {
-        if (get_default || PREF_IS_LOCKED(pref) || !PREF_HAS_USER_VALUE(pref))
-        {
+    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->flags & PREF_HAS_DEFAULT) {
+            if (pref->prefFlags.HasDefault()) {
                 *return_value = tempBool;
                 rv = NS_OK;
             }
-        }
-        else {
+        } else {
             *return_value = pref->userPref.boolVal;
             rv = NS_OK;
         }
     }
     return rv;
 }
 
 nsresult
@@ -579,21 +565,20 @@ PREF_DeleteBranch(const char *branch_nam
 
 nsresult
 PREF_ClearUserPref(const char *pref_name)
 {
     if (!gHashTable)
         return NS_ERROR_NOT_INITIALIZED;
 
     PrefHashEntry* pref = pref_HashTableLookup(pref_name);
-    if (pref && PREF_HAS_USER_VALUE(pref))
-    {
-        pref->flags &= ~PREF_USERSET;
+    if (pref && pref->prefFlags.HasUserValue()) {
+        pref->prefFlags.SetHasUserValue(false);
 
-        if (!(pref->flags & PREF_HAS_DEFAULT)) {
+        if (!pref->prefFlags.HasDefault()) {
             gHashTable->RemoveEntry(pref);
         }
 
         pref_DoCallback(pref_name);
         gDirty = true;
     }
     return NS_OK;
 }
@@ -607,21 +592,21 @@ PREF_ClearAllUserPrefs()
 
     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_HAS_USER_VALUE(pref)) {
+        if (pref->prefFlags.HasUserValue()) {
             prefStrings.push_back(std::string(pref->key));
 
-            pref->flags &= ~PREF_USERSET;
-            if (!(pref->flags & PREF_HAS_DEFAULT)) {
+            pref->prefFlags.SetHasUserValue(false);
+            if (!pref->prefFlags.HasDefault()) {
                 iter.Remove();
             }
         }
     }
 
     for (std::string& prefString : prefStrings) {
         pref_DoCallback(prefString.c_str());
     }
@@ -635,71 +620,76 @@ nsresult PREF_LockPref(const char *key, 
     if (!gHashTable)
         return NS_ERROR_NOT_INITIALIZED;
 
     PrefHashEntry* pref = pref_HashTableLookup(key);
     if (!pref)
         return NS_ERROR_UNEXPECTED;
 
     if (lockit) {
-        if (!PREF_IS_LOCKED(pref))
-        {
-            pref->flags |= PREF_LOCKED;
+        if (!pref->prefFlags.IsLocked()) {
+            pref->prefFlags.SetLocked(true);
             gIsAnyPrefLocked = true;
             pref_DoCallback(key);
         }
-    }
-    else
-    {
-        if (PREF_IS_LOCKED(pref))
-        {
-            pref->flags &= ~PREF_LOCKED;
+    } 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;
-    if (type & PREF_STRING)
-    {
-        if (oldValue.stringVal && newValue.stringVal)
+    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;
     }
-    else if (type & PREF_INT)
-        changed = oldValue.intVal != newValue.intVal;
-    else if (type & PREF_BOOL)
-        changed = oldValue.boolVal != newValue.boolVal;
     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 void pref_SetValue(PrefValue* existingValue, uint16_t *existingFlags,
-                          PrefValue newValue, PrefType newType)
+static PrefTypeFlags pref_SetValue(PrefValue* existingValue, PrefTypeFlags flags,
+                                   PrefValue newValue, PrefType newType)
 {
-    if ((*existingFlags & PREF_STRING) && existingValue->stringVal) {
+    if (flags.IsTypeString() && existingValue->stringVal) {
         PL_strfree(existingValue->stringVal);
     }
-    *existingFlags = (*existingFlags & ~PREF_VALUETYPE_MASK) | newType;
-    if (newType & PREF_STRING) {
+    flags.SetPrefType(newType);
+    if (flags.IsTypeString()) {
         PR_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
 
@@ -718,73 +708,63 @@ nsresult pref_HashPref(const char *key, 
     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->flags = type;
+        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->flags & PREF_HAS_DEFAULT) && PREF_TYPE(pref) != type)
-    {
+    } 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_IS_LOCKED(pref))
-        {       /* ?? change of semantics? */
+    if (flags & kPrefSetDefault) {
+        if (!pref->prefFlags.IsLocked()) {
+            /* ?? change of semantics? */
             if (pref_ValueChanged(pref->defaultPref, value, type) ||
-                !(pref->flags & PREF_HAS_DEFAULT))
-            {
-                pref_SetValue(&pref->defaultPref, &pref->flags, value, type);
-                pref->flags |= PREF_HAS_DEFAULT;
-                if (flags & kPrefStickyDefault)
-                    pref->flags |= PREF_STICKY_DEFAULT;
-                if (!PREF_HAS_USER_VALUE(pref))
+                !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
-    {
+    } 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->flags & PREF_HAS_DEFAULT) &&
-            !(pref->flags & PREF_STICKY_DEFAULT) &&
+        if ((pref->prefFlags.HasDefault()) &&
+            !(pref->prefFlags.HasStickyDefault()) &&
             !pref_ValueChanged(pref->defaultPref, value, type) &&
-            !(flags & kPrefForceSet))
-        {
-            if (PREF_HAS_USER_VALUE(pref))
-            {
+            !(flags & kPrefForceSet)) {
+            if (pref->prefFlags.HasUserValue()) {
                 /* XXX should we free a user-set string value if there is one? */
-                pref->flags &= ~PREF_USERSET;
-                if (!PREF_IS_LOCKED(pref)) {
+                pref->prefFlags.SetHasUserValue(false);
+                if (!pref->prefFlags.IsLocked()) {
                     gDirty = true;
                     valueChanged = true;
                 }
             }
-        }
-        else if (!PREF_HAS_USER_VALUE(pref) ||
-                 PREF_TYPE(pref) != type ||
-                 pref_ValueChanged(pref->userPref, value, type) )
-        {
-            pref_SetValue(&pref->userPref, &pref->flags, value, type);
-            pref->flags |= PREF_USERSET;
-            if (!PREF_IS_LOCKED(pref)) {
+        } 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()) {
                 gDirty = true;
                 valueChanged = true;
             }
         }
     }
 
     if (valueChanged) {
         return pref_DoCallback(key);
@@ -803,39 +783,34 @@ pref_SizeOfPrivateData(MallocSizeOf aMal
     return n;
 }
 
 PrefType
 PREF_GetPrefType(const char *pref_name)
 {
     if (gHashTable) {
         PrefHashEntry* pref = pref_HashTableLookup(pref_name);
-        if (pref)
-        {
-            if (pref->flags & PREF_STRING)
-                return PREF_STRING;
-            else if (pref->flags & PREF_INT)
-                return PREF_INT;
-            else if (pref->flags & PREF_BOOL)
-                return PREF_BOOL;
+        if (pref) {
+            return pref->prefFlags.GetPrefType();
         }
     }
-    return PREF_INVALID;
+    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_IS_LOCKED(pref))
+        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,
@@ -968,15 +943,21 @@ static nsresult pref_DoCallback(const ch
 }
 
 void PREF_ReaderCallback(void       *closure,
                          const char *pref,
                          PrefValue   value,
                          PrefType    type,
                          bool        isDefault,
                          bool        isStickyDefault)
+
 {
-    uint32_t flags = isDefault ? kPrefSetDefault : kPrefForceSet;
-    if (isDefault && isStickyDefault) {
-        flags |= kPrefStickyDefault;
+    uint32_t flags = 0;
+    if (isDefault) {
+        flags |= kPrefSetDefault;
+        if (isStickyDefault) {
+            flags |= kPrefStickyDefault;
+        }
+    } else {
+        flags |= kPrefForceSet;
     }
     pref_HashPref(pref, value, type, flags);
 }
--- a/modules/libpref/prefapi.h
+++ b/modules/libpref/prefapi.h
@@ -23,58 +23,115 @@ static const uint32_t MAX_ADVISABLE_PREF
 
 typedef union
 {
     char*       stringVal;
     int32_t     intVal;
     bool        boolVal;
 } PrefValue;
 
-struct PrefHashEntry : PLDHashEntryHdr
-{
-    uint16_t flags; // This field goes first to minimize struct size on 64-bit.
-    const char *key;
-    PrefValue defaultPref;
-    PrefValue userPref;
-};
-
 /*
 // <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 
+// 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
+// Preference flags, including the native type of the preference. Changing any of these
+// values will require modifying the code inside of PrefTypeFlags class.
 // </font>
 */
 
-typedef enum { PREF_INVALID = 0,
-               PREF_LOCKED = 1, PREF_USERSET = 2, PREF_CONFIG = 4, PREF_REMOTE = 8,
-               PREF_LILOCAL = 16, PREF_STRING = 32, PREF_INT = 64, PREF_BOOL = 128,
-               PREF_HAS_DEFAULT = 256,
-               // pref is default pref with "sticky" semantics
-               PREF_STICKY_DEFAULT = 512,
-               PREF_VALUETYPE_MASK = (PREF_STRING | PREF_INT | PREF_BOOL)
-             } PrefType;
+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)) {}
+  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").  
+// 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.
@@ -98,18 +155,18 @@ bool     PREF_HasUserPref(const char* pr
 // 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);	
+                           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);
@@ -168,20 +225,20 @@ typedef void (*PrefChangedFunc) (const c
 /*
 // <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 );
+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,
--- a/modules/libpref/prefread.cpp
+++ b/modules/libpref/prefread.cpp
@@ -109,27 +109,27 @@ pref_GrowBuf(PrefParseState *ps)
  * @return false to indicate a fatal error.
  */
 static bool
 pref_DoCallback(PrefParseState *ps)
 {
     PrefValue  value;
 
     switch (ps->vtype) {
-    case PREF_STRING:
+    case PrefType::String:
         value.stringVal = ps->vb;
         break;
-    case PREF_INT:
+    case PrefType::Int:
         if ((ps->vb[0] == '-' || ps->vb[0] == '+') && ps->vb[1] == '\0') {
             NS_WARNING("malformed integer value");
             return false;
         }
         value.intVal = atoi(ps->vb);
         break;
-    case PREF_BOOL:
+    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;
@@ -149,17 +149,17 @@ PREF_FinalizeParseState(PrefParseState *
     if (ps->lb)
         free(ps->lb);
 }
 
 /**
  * Pseudo-BNF
  * ----------
  * function      = LJUNK function-name JUNK function-args
- * function-name = "user_pref" | "pref"
+ * 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)>
@@ -183,32 +183,37 @@ PREF_ParseBuf(PrefParseState *ps, const 
     for (end = buf + bufLen; buf != end; ++buf) {
         c = *buf;
         switch (state) {
         /* initial state */
         case PREF_PARSE_INIT:
             if (ps->lbcur != ps->lb) { /* reset state */
                 ps->lbcur = ps->lb;
                 ps->vb    = nullptr;
-                ps->vtype = PREF_INVALID;
+                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 */
-            case 's':       /* indicating sticky_pref */
-                ps->smatch = (c == 'u' ? kUserPref :
-                             (c == 's' ? kPrefSticky : kPref));
+                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;
 
@@ -243,16 +248,18 @@ PREF_ParseBuf(PrefParseState *ps, const 
             else
                 *ps->lbcur++ = c;
             break;
 
         /* name parsing */
         case PREF_PARSE_UNTIL_NAME:
             if (c == '\"' || c == '\'') {
                 ps->fdefault = (ps->smatch == kPref || ps->smatch == kPrefSticky);
+                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;
@@ -279,31 +286,31 @@ PREF_ParseBuf(PrefParseState *ps, const 
             }
             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 = PREF_STRING;
+                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 = PREF_BOOL;
+                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 = PREF_INT;
+                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 */
@@ -506,23 +513,22 @@ PREF_ParseBuf(PrefParseState *ps, const 
             }
             else if (!isspace(c)) {
                 NS_WARNING("malformed pref file");
                 return false;
             }
             break;
         case PREF_PARSE_UNTIL_CLOSE_PAREN:
             /* tolerate only whitespace and embedded comments  */
-            if (c == ')')
+            if (c == ')') {
                 state = PREF_PARSE_UNTIL_SEMICOLON;
-            else if (c == '/') {
+            } else if (c == '/') {
                 ps->nextstate = state; /* return here when done with comment */
                 state = PREF_PARSE_COMMENT_MAYBE_START;
-            }
-            else if (!isspace(c)) {
+            } else if (!isspace(c)) {
                 NS_WARNING("malformed pref file");
                 return false;
             }
             break;
 
         /* function terminator ';' parsing */
         case PREF_PARSE_UNTIL_SEMICOLON:
             /* tolerate only whitespace and embedded comments */
--- a/modules/libpref/prefread.h
+++ b/modules/libpref/prefread.h
@@ -49,17 +49,17 @@ typedef struct PrefParseState {
     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        fdefault;   /* true if (default) pref        */
     bool        fstickydefault; /* true if (sticky) pref     */
 } PrefParseState;
 
 /**
  * PREF_InitParseState
  *
  * Called to initialize a PrefParseState instance.
  *