Bug 783184: Ensure that child-process pref state always is the same as its parent's. r=bsmedberg
authorChris Jones <jones.chris.g@gmail.com>
Wed, 22 Aug 2012 13:00:21 -0700
changeset 103057 5253021171872eada9416ea7294a53588cec7408
parent 103056 67c5213dfe2b944d0c2d019f9a47cb7da74823a2
child 103058 739eef9dbbdded722f8e97ad6ac41283e457350d
push id23326
push useremorley@mozilla.com
push dateThu, 23 Aug 2012 10:36:26 +0000
treeherdermozilla-central@198ca6edd0ae [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbsmedberg
bugs783184
milestone17.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 783184: Ensure that child-process pref state always is the same as its parent's. r=bsmedberg
dom/ipc/ContentChild.cpp
dom/ipc/ContentChild.h
dom/ipc/ContentParent.cpp
dom/ipc/ContentParent.h
dom/ipc/PContent.ipdl
modules/libpref/public/Makefile.in
modules/libpref/public/PPrefTuple.h
modules/libpref/public/PrefTuple.h
modules/libpref/public/Preferences.h
modules/libpref/src/Preferences.cpp
modules/libpref/src/prefapi.cpp
modules/libpref/src/prefapi_private_data.h
--- a/dom/ipc/ContentChild.cpp
+++ b/dom/ipc/ContentChild.cpp
@@ -752,26 +752,19 @@ ContentChild::AddRemoteAlertObserver(con
                                      nsIObserver* aObserver)
 {
     NS_ASSERTION(aObserver, "Adding a null observer?");
     mAlertObservers.AppendElement(new AlertObserver(aObserver, aData));
     return NS_OK;
 }
 
 bool
-ContentChild::RecvPreferenceUpdate(const PrefTuple& aPref)
+ContentChild::RecvPreferenceUpdate(const PrefSetting& aPref)
 {
-    Preferences::SetPreference(&aPref);
-    return true;
-}
-
-bool
-ContentChild::RecvClearUserPreference(const nsCString& aPrefName)
-{
-    Preferences::ClearContentPref(aPrefName.get());
+    Preferences::SetPreference(aPref);
     return true;
 }
 
 bool
 ContentChild::RecvNotifyAlertsObserver(const nsCString& aType, const nsString& aData)
 {
     for (uint32_t i = 0; i < mAlertObservers.Length();
          /*we mutate the array during the loop; ++i iff no mutation*/) {
--- a/dom/ipc/ContentChild.h
+++ b/dom/ipc/ContentChild.h
@@ -131,18 +131,17 @@ public:
                                     const nsCString& locale);
 
     virtual bool RecvSetOffline(const bool& offline);
 
     virtual bool RecvNotifyVisited(const IPC::URI& aURI);
     // auto remove when alertfinished is received.
     nsresult AddRemoteAlertObserver(const nsString& aData, nsIObserver* aObserver);
 
-    virtual bool RecvPreferenceUpdate(const PrefTuple& aPref);
-    virtual bool RecvClearUserPreference(const nsCString& aPrefName);
+    virtual bool RecvPreferenceUpdate(const PrefSetting& aPref);
 
     virtual bool RecvNotifyAlertsObserver(const nsCString& aType, const nsString& aData);
 
     virtual bool RecvAsyncMessage(const nsString& aMsg,
                                   const ClonedMessageData& aData);
 
     virtual bool RecvGeolocationUpdate(const GeoPosition& somewhere);
 
--- a/dom/ipc/ContentParent.cpp
+++ b/dom/ipc/ContentParent.cpp
@@ -727,19 +727,19 @@ ContentParent::IsAlive()
 
 bool
 ContentParent::IsForApp()
 {
     return !mAppManifestURL.IsEmpty();
 }
 
 bool
-ContentParent::RecvReadPrefsArray(InfallibleTArray<PrefTuple> *prefs)
+ContentParent::RecvReadPrefsArray(InfallibleTArray<PrefSetting>* aPrefs)
 {
-    Preferences::MirrorPreferences(prefs);
+    Preferences::GetPreferences(aPrefs);
     return true;
 }
 
 bool
 ContentParent::RecvReadFontList(InfallibleTArray<FontListEntry>* retValue)
 {
 #ifdef ANDROID
     gfxAndroidPlatform::GetPlatform()->GetFontList(retValue);
@@ -949,27 +949,20 @@ ContentParent::Observe(nsISupports* aSub
     if (!strcmp(aTopic, "memory-pressure")) {
         unused << SendFlushMemory(nsDependentString(aData));
     }
     // listening for remotePrefs...
     else if (!strcmp(aTopic, "nsPref:changed")) {
         // We know prefs are ASCII here.
         NS_LossyConvertUTF16toASCII strData(aData);
 
-        PrefTuple pref;
-        bool prefNeedUpdate = Preferences::MirrorPreference(strData.get(), &pref);
-        if (prefNeedUpdate) {
-          if (!SendPreferenceUpdate(pref)) {
-              return NS_ERROR_NOT_AVAILABLE;
-          }
-        } else {
-          // Pref wasn't found.  It was probably removed.
-          if (!SendClearUserPreference(strData)) {
-              return NS_ERROR_NOT_AVAILABLE;
-          }
+        PrefSetting pref(strData, null_t(), null_t());
+        Preferences::GetPreference(&pref);
+        if (!SendPreferenceUpdate(pref)) {
+            return NS_ERROR_NOT_AVAILABLE;
         }
     }
     else if (!strcmp(aTopic, NS_IPC_IOSERVICE_SET_OFFLINE_TOPIC)) {
       NS_ConvertUTF16toUTF8 dataStr(aData);
       const char *offline = dataStr.get();
       if (!SendSetOffline(!strcmp(offline, "true") ? true : false))
           return NS_ERROR_NOT_AVAILABLE;
     }
--- a/dom/ipc/ContentParent.h
+++ b/dom/ipc/ContentParent.h
@@ -207,17 +207,17 @@ private:
     virtual bool DeallocPExternalHelperApp(PExternalHelperAppParent* aService);
 
     virtual PSmsParent* AllocPSms();
     virtual bool DeallocPSms(PSmsParent*);
 
     virtual PStorageParent* AllocPStorage(const StorageConstructData& aData);
     virtual bool DeallocPStorage(PStorageParent* aActor);
 
-    virtual bool RecvReadPrefsArray(InfallibleTArray<PrefTuple> *retValue);
+    virtual bool RecvReadPrefsArray(InfallibleTArray<PrefSetting>* aPrefs);
     virtual bool RecvReadFontList(InfallibleTArray<FontListEntry>* retValue);
 
     virtual bool RecvReadPermissions(InfallibleTArray<IPC::Permission>* aPermissions);
 
     virtual bool RecvSetClipboardText(const nsString& text, const bool& isPrivateData, const int32_t& whichClipboard);
     virtual bool RecvGetClipboardText(const int32_t& whichClipboard, nsString* text);
     virtual bool RecvEmptyClipboard();
     virtual bool RecvClipboardHasText(bool* hasText);
--- a/dom/ipc/PContent.ipdl
+++ b/dom/ipc/PContent.ipdl
@@ -19,17 +19,16 @@ include protocol PSms;
 include protocol PStorage;
 include protocol PTestShell;
 
 include "mozilla/chrome/RegistryMessageUtils.h";
 include "mozilla/net/NeckoMessageUtils.h";
 include "mozilla/dom/TabMessageUtils.h";
 
 include "nsGeoPositionIPCSerialiser.h";
-include "PPrefTuple.h";
 
 include DOMTypes;
 
 using GeoPosition;
 using PrefTuple;
 
 using ChromePackage;
 using ResourceMapping;
@@ -130,16 +129,33 @@ union BlobConstructorParams
   MysteryBlobConstructorParams;
 };
 
 union AppId {
   uint32_t;
   nullable PBrowser;
 };
 
+union PrefValue {
+  nsCString;
+  int32_t;
+  bool;
+};
+
+union MaybePrefValue {
+  PrefValue;
+  null_t;
+};
+
+struct PrefSetting {
+  nsCString name;
+  MaybePrefValue defaultValue;
+  MaybePrefValue userValue;
+};
+
 rpc protocol PContent
 {
     parent opens PCompositor;
 
     manages PAudio;
     manages PBlob;
     manages PBrowser;
     manages PCrashReporter;
@@ -178,18 +194,17 @@ child:
 
     RegisterChrome(ChromePackage[] packages, ResourceMapping[] resources,
                    OverrideMapping[] overrides, nsCString locale);
 
     async SetOffline(bool offline);
 
     async NotifyVisited(URI uri);
 
-    PreferenceUpdate(PrefTuple pref);
-    ClearUserPreference(nsCString prefName);
+    PreferenceUpdate(PrefSetting pref);
 
     NotifyAlertsObserver(nsCString topic, nsString data);
 
     GeolocationUpdate(GeoPosition somewhere);
 
     // nsIPermissionManager messages
     AddPermission(Permission permission);
 
@@ -243,17 +258,17 @@ parent:
     sync ShowFilePicker(int16_t mode, int16_t selectedType, bool addToRecentDocs,
                         nsString title, nsString defaultFile, nsString defaultExtension,
                         nsString[] filters, nsString[] filterNames)
         returns (nsString[] files, int16_t retValue, nsresult result);
 
     async LoadURIExternal(URI uri);
 
     // PrefService message
-    sync ReadPrefsArray() returns (PrefTuple[] retValue);
+    sync ReadPrefsArray() returns (PrefSetting[] prefs);
 
     sync ReadFontList() returns (FontListEntry[] retValue);
 
     sync SyncMessage(nsString aMessage, ClonedMessageData aData)
       returns (nsString[] retval);
 
     ShowAlertNotification(nsString imageUrl, 
                           nsString title, 
--- a/modules/libpref/public/Makefile.in
+++ b/modules/libpref/public/Makefile.in
@@ -22,19 +22,14 @@ SDK_XPIDLSRCS   = \
               nsIPrefLocalizedString.idl \
               $(NULL)
 
 XPIDLSRCS	= \
               nsIPrefBranchInternal.idl \
               nsIRelativeFilePref.idl \
               $(NULL)
 
-EXPORTS     = \
-              PPrefTuple.h \
-              PrefTuple.h \
-              $(NULL)
-
 EXPORTS_mozilla = \
               Preferences.h \
               $(NULL)
 
 include $(topsrcdir)/config/rules.mk
 
deleted file mode 100644
--- a/modules/libpref/public/PPrefTuple.h
+++ /dev/null
@@ -1,74 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#ifndef dom_pref_hash_entry_array_IPC_serialiser
-#define dom_pref_hash_entry_array_IPC_serialiser
-
-#include "IPC/IPCMessageUtils.h"
-#include "nsTArray.h"
-#include "pldhash.h"
-#include "nsIPrefService.h"
-#include "PrefTuple.h"
-
-
-namespace IPC {
-
-template <>
-struct ParamTraits<PrefTuple>
-{
-  typedef PrefTuple paramType;
-
-  // Function to serialize a PrefTuple
-  static void Write(Message *aMsg, const paramType& aParam)
-  {
-    WriteParam(aMsg, aParam.key);
-    WriteParam(aMsg, (uint32_t)aParam.type);
-    switch (aParam.type) {
-      case PrefTuple::PREF_STRING:
-        WriteParam(aMsg, aParam.stringVal);
-        break;
-      case PrefTuple::PREF_INT:
-        WriteParam(aMsg, aParam.intVal);
-        break;
-      case PrefTuple::PREF_BOOL:
-        WriteParam(aMsg, aParam.boolVal);
-        break;
-    }
-  }
-
-  // Function to de-serialize a PrefTuple
-  static bool Read(const Message* aMsg, void **aIter, paramType* aResult)
-  {
-    uint32_t type;
-
-    if (!ReadParam(aMsg, aIter, &(aResult->key)))
-      return false;
-
-    if (!ReadParam(aMsg, aIter, &type))
-      return false;
-
-    switch (type) {
-      case PrefTuple::PREF_STRING:
-        aResult->type = PrefTuple::PREF_STRING;
-        if (!ReadParam(aMsg, aIter, &(aResult->stringVal)))
-          return false;
-        break;
-      case PrefTuple::PREF_INT:
-        aResult->type = PrefTuple::PREF_INT;
-        if (!ReadParam(aMsg, aIter, &(aResult->intVal)))
-          return false;
-        break;
-      case PrefTuple::PREF_BOOL:
-        aResult->type = PrefTuple::PREF_BOOL;
-        if (!ReadParam(aMsg, aIter, &(aResult->boolVal)))
-          return false;
-        break;
-    }
-    return true;
-  }
-} ;
-
-}
-#endif
-
deleted file mode 100644
--- a/modules/libpref/public/PrefTuple.h
+++ /dev/null
@@ -1,30 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#ifndef preftuple_included
-#define preftuple_included
-
-#include "nsTArray.h"
-#include "nsString.h"
-
-struct PrefTuple
-{
-  nsCAutoString key;
-
-  // We don't use a union to avoid allocations when using the string component
-  // NOTE: Only one field will be valid at any given time, as indicated by the type enum
-  nsCAutoString stringVal;
-  int32_t       intVal;
-  bool          boolVal;
-
-  enum {
-    PREF_STRING,
-    PREF_INT,
-    PREF_BOOL
-  } type;
-
-};
-
-#endif
-
--- a/modules/libpref/public/Preferences.h
+++ b/modules/libpref/public/Preferences.h
@@ -10,37 +10,44 @@
 #error "This header is only usable from within libxul (MOZILLA_INTERNAL_API)."
 #endif
 
 #include "nsIPrefService.h"
 #include "nsIPrefBranch.h"
 #include "nsIPrefBranchInternal.h"
 #include "nsIObserver.h"
 #include "nsCOMPtr.h"
+#include "nsTArray.h"
 #include "nsWeakReference.h"
 
 class nsIFile;
 class nsCString;
 class nsString;
 class nsAdoptingString;
 class nsAdoptingCString;
 
 #ifndef have_PrefChangedFunc_typedef
 typedef int (*PR_CALLBACK PrefChangedFunc)(const char *, void *);
 #define have_PrefChangedFunc_typedef
 #endif
 
 namespace mozilla {
 
+namespace dom {
+class PrefSetting;
+}
+
 class Preferences : public nsIPrefService,
                     public nsIObserver,
                     public nsIPrefBranchInternal,
                     public nsSupportsWeakReference
 {
 public:
+  typedef mozilla::dom::PrefSetting PrefSetting;
+
   NS_DECL_ISUPPORTS
   NS_DECL_NSIPREFSERVICE
   NS_FORWARD_NSIPREFBRANCH(sRootBranch->)
   NS_DECL_NSIOBSERVER
 
   Preferences();
   virtual ~Preferences();
 
@@ -315,21 +322,19 @@ public:
                                     void** aResult);
 
   /**
    * Gets the type of the pref.
    */
   static int32_t GetDefaultType(const char* aPref);
 
   // Used to synchronise preferences between chrome and content processes.
-  static void MirrorPreferences(nsTArray<PrefTuple,
-                                nsTArrayInfallibleAllocator> *aArray);
-  static bool MirrorPreference(const char *aPref, PrefTuple *aTuple);
-  static void ClearContentPref(const char *aPref);
-  static void SetPreference(const PrefTuple *aTuple);
+  static void GetPreferences(InfallibleTArray<PrefSetting>* aPrefs);
+  static void GetPreference(PrefSetting* aPref);
+  static void SetPreference(const PrefSetting& aPref);
 
 protected:
   nsresult NotifyServiceObservers(const char *aSubject);
   /**
    * Reads the default pref file or, if that failed, try to save a new one.
    *
    * @return NS_OK if either action succeeded,
    *         or the error code related to the read attempt.
--- a/modules/libpref/src/Preferences.cpp
+++ b/modules/libpref/src/Preferences.cpp
@@ -31,17 +31,16 @@
 
 #include "nsQuickSort.h"
 #include "prmem.h"
 #include "pldhash.h"
 
 #include "prefapi.h"
 #include "prefread.h"
 #include "prefapi_private_data.h"
-#include "PrefTuple.h"
 
 #include "mozilla/Omnijar.h"
 #include "nsZipArchive.h"
 
 #include "nsTArray.h"
 #include "nsRefPtrHashtable.h"
 
 namespace mozilla {
@@ -280,23 +279,22 @@ Preferences::Init()
   rv = PREF_Init();
   NS_ENSURE_SUCCESS(rv, rv);
 
   rv = pref_InitInitialObjects();
   NS_ENSURE_SUCCESS(rv, rv);
 
   using mozilla::dom::ContentChild;
   if (XRE_GetProcessType() == GeckoProcessType_Content) {
-    InfallibleTArray<PrefTuple> array;
-    ContentChild::GetSingleton()->SendReadPrefsArray(&array);
+    InfallibleTArray<PrefSetting> prefs;
+    ContentChild::GetSingleton()->SendReadPrefsArray(&prefs);
 
     // Store the array
-    nsTArray<PrefTuple>::size_type index = array.Length();
-    while (index-- > 0) {
-      pref_SetPrefTuple(array[index], true);
+    for (uint32_t i = 0; i < prefs.Length(); ++i) {
+      pref_SetPref(prefs[i]);
     }
     return NS_OK;
   }
 
   nsXPIDLCString lockFileName;
   /*
    * The following is a small hack which will allow us to only load the library
    * which supports the netscape.cfg file if the preference is defined. We
@@ -465,44 +463,36 @@ ReadExtensionPrefs(nsIFile *aFile)
       PREF_ParseBuf(&ps, buffer, read);
     }
     PREF_FinalizeParseState(&ps);
   }
   return rv;
 }
 
 void
-Preferences::SetPreference(const PrefTuple *aPref)
+Preferences::SetPreference(const PrefSetting& aPref)
 {
-  pref_SetPrefTuple(*aPref, true);
+  pref_SetPref(aPref);
 }
 
 void
-Preferences::ClearContentPref(const char *aPref)
+Preferences::GetPreference(PrefSetting* aPref)
 {
-  PREF_ClearUserPref(aPref);
-}
+  PrefHashEntry *entry = pref_HashTableLookup(aPref->name().get());
+  if (!entry)
+    return;
 
-bool
-Preferences::MirrorPreference(const char *aPref, PrefTuple *aTuple)
-{
-  PrefHashEntry *entry = pref_HashTableLookup(aPref);
-  if (!entry)
-    return false;
-
-  pref_GetTupleFromEntry(entry, aTuple);
-  return true;
+  pref_GetPrefFromEntry(entry, aPref);
 }
 
 void
-Preferences::MirrorPreferences(nsTArray<PrefTuple,
-                                        nsTArrayInfallibleAllocator> *aArray)
+Preferences::GetPreferences(InfallibleTArray<PrefSetting>* aPrefs)
 {
-  aArray->SetCapacity(PL_DHASH_TABLE_SIZE(&gHashTable));
-  PL_DHashTableEnumerate(&gHashTable, pref_MirrorPrefs, aArray);
+  aPrefs->SetCapacity(PL_DHASH_TABLE_SIZE(&gHashTable));
+  PL_DHashTableEnumerate(&gHashTable, pref_GetPrefs, aPrefs);
 }
 
 NS_IMETHODIMP
 Preferences::GetBranch(const char *aPrefRoot, nsIPrefBranch **_retval)
 {
   nsresult rv;
 
   if ((nullptr != aPrefRoot) && (*aPrefRoot != '\0')) {
--- a/modules/libpref/src/prefapi.cpp
+++ b/modules/libpref/src/prefapi.cpp
@@ -1,16 +1,17 @@
-/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
+#include "base/basictypes.h"
+
 #include "prefapi.h"
 #include "prefapi_private_data.h"
-#include "PrefTuple.h"
 #include "prefread.h"
 #include "nsReadableUtils.h"
 #include "nsCRT.h"
 
 #define PL_ARENA_CONST_ALIGN_MASK 3
 #include "plarena.h"
 
 #ifdef XP_OS2
@@ -21,26 +22,29 @@
 #endif /* _WIN32 */
 
 #include "plstr.h"
 #include "pldhash.h"
 #include "plbase64.h"
 #include "prlog.h"
 #include "prmem.h"
 #include "prprf.h"
+#include "mozilla/dom/PContent.h"
 #include "nsQuickSort.h"
 #include "nsString.h"
 #include "nsPrintfCString.h"
 #include "prlink.h"
 
 #ifdef XP_OS2
 #define INCL_DOS
 #include <os2.h>
 #endif
 
+using namespace mozilla;
+
 static void
 clearPrefEntry(PLDHashTable *table, PLDHashEntryHdr *entry)
 {
     PrefHashEntry *pref = static_cast<PrefHashEntry *>(entry);
     if (pref->flags & PREF_STRING)
     {
         if (pref->defaultPref.stringVal)
             PL_strfree(pref->defaultPref.stringVal);
@@ -116,16 +120,17 @@ static char *ArenaStrDup(const char* str
     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;
@@ -266,32 +271,63 @@ 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);
 }
 
-nsresult
-pref_SetPrefTuple(const PrefTuple &aPref, bool set_default)
+enum WhichValue { DEFAULT_VALUE, USER_VALUE };
+static nsresult
+SetPrefValue(const char* aPrefName, const dom::PrefValue& aValue,
+             WhichValue aWhich)
 {
-    switch (aPref.type) {
-        case PrefTuple::PREF_STRING:
-            return PREF_SetCharPref(aPref.key.get(), aPref.stringVal.get(), set_default);
+    bool setDefault = (aWhich == DEFAULT_VALUE);
+    switch (aValue.type()) {
+    case dom::PrefValue::TnsCString:
+        return PREF_SetCharPref(aPrefName, aValue.get_nsCString().get(),
+                                setDefault);
+    case dom::PrefValue::Tint32_t:
+        return PREF_SetIntPref(aPrefName, aValue.get_int32_t(),
+                               setDefault);
+    case dom::PrefValue::Tbool:
+        return PREF_SetBoolPref(aPrefName, aValue.get_bool(),
+                                setDefault);
+    default:
+        MOZ_NOT_REACHED();
+        return NS_ERROR_FAILURE;
+    }
+}
 
-        case PrefTuple::PREF_INT:
-            return PREF_SetIntPref(aPref.key.get(), aPref.intVal, set_default);
+nsresult
+pref_SetPref(const dom::PrefSetting& aPref)
+{
+    const char* prefName = aPref.name().get();
+    const dom::MaybePrefValue& defaultValue = aPref.defaultValue();
+    const dom::MaybePrefValue& userValue = aPref.userValue();
 
-        case PrefTuple::PREF_BOOL:
-            return PREF_SetBoolPref(aPref.key.get(), aPref.boolVal, set_default);
+    nsresult rv;
+    if (defaultValue.type() == dom::MaybePrefValue::TPrefValue) {
+        rv = SetPrefValue(prefName, defaultValue.get_PrefValue(), DEFAULT_VALUE);
+        if (NS_FAILED(rv)) {
+            return rv;
+        }
     }
 
-    NS_NOTREACHED("Unknown type");
-    return NS_ERROR_INVALID_ARG;
+    if (userValue.type() == dom::MaybePrefValue::TPrefValue) {
+        rv = SetPrefValue(prefName, userValue.get_PrefValue(), USER_VALUE);
+    } else {
+        rv = PREF_ClearUserPref(prefName);      
+    }
+
+    // NB: we should never try to clear a default value, that doesn't
+    // make sense
+
+    return rv;
 }
 
 PLDHashOperator
 pref_savePref(PLDHashTable *table, PLDHashEntryHdr *heh, uint32_t i, void *arg)
 {
     pref_saveArgs *argData = static_cast<pref_saveArgs *>(arg);
     PrefHashEntry *pref = static_cast<PrefHashEntry *>(heh);
 
@@ -343,55 +379,81 @@ pref_savePref(PLDHashTable *table, PLDHa
                                          NS_LITERAL_CSTRING("\", ") +
                                          prefValue +
                                          NS_LITERAL_CSTRING(");"));
 
     return PL_DHASH_NEXT;
 }
 
 PLDHashOperator
-pref_MirrorPrefs(PLDHashTable *table,
-                 PLDHashEntryHdr *heh,
-                 uint32_t i,
-                 void *arg)
+pref_GetPrefs(PLDHashTable *table,
+              PLDHashEntryHdr *heh,
+              uint32_t i,
+              void *arg)
 {
     if (heh) {
         PrefHashEntry *entry = static_cast<PrefHashEntry *>(heh);
-        PrefTuple *newEntry =
-            static_cast<nsTArray<PrefTuple> *>(arg)->AppendElement();
+        dom::PrefSetting *pref =
+            static_cast<InfallibleTArray<dom::PrefSetting>*>(arg)->AppendElement();
 
-        pref_GetTupleFromEntry(entry, newEntry);
+        pref_GetPrefFromEntry(entry, pref);
     }
     return PL_DHASH_NEXT;
 }
 
-void
-pref_GetTupleFromEntry(PrefHashEntry *aHashEntry, PrefTuple *aTuple)
+static void
+GetPrefValueFromEntry(PrefHashEntry *aHashEntry, dom::PrefSetting* aPref,
+                      WhichValue aWhich)
 {
-    aTuple->key = aHashEntry->key;
-
-    PrefValue *value = PREF_HAS_USER_VALUE(aHashEntry) ?
-        &(aHashEntry->userPref) : &(aHashEntry->defaultPref);
+    PrefValue* value;
+    dom::PrefValue* settingValue;
+    if (aWhich == USER_VALUE) {
+        value = &aHashEntry->userPref;
+        aPref->userValue() = dom::PrefValue();
+        settingValue = &aPref->userValue().get_PrefValue();
+    } else {
+        value = &aHashEntry->defaultPref;
+        aPref->defaultValue() = dom::PrefValue();
+        settingValue = &aPref->defaultValue().get_PrefValue();
+    }
 
     switch (aHashEntry->flags & PREF_VALUETYPE_MASK) {
-        case PREF_STRING:
-            aTuple->stringVal = value->stringVal;
-            aTuple->type = PrefTuple::PREF_STRING;
-            return;
+    case PREF_STRING:
+        *settingValue = nsDependentCString(value->stringVal);
+        return;
+    case PREF_INT:
+        *settingValue = value->intVal;
+        return;
+    case PREF_BOOL:
+        *settingValue = !!value->boolVal;
+        return;
+    default:
+        MOZ_NOT_REACHED();
+    }
+}
 
-        case PREF_INT:
-            aTuple->intVal = value->intVal;
-            aTuple->type = PrefTuple::PREF_INT;
-            return;
+void
+pref_GetPrefFromEntry(PrefHashEntry *aHashEntry, dom::PrefSetting* aPref)
+{
+    aPref->name() = aHashEntry->key;
+    if (PREF_HAS_DEFAULT_VALUE(aHashEntry)) {
+        GetPrefValueFromEntry(aHashEntry, aPref, DEFAULT_VALUE);
+    } else {
+        aPref->defaultValue() = null_t();
+    }
+    if (PREF_HAS_USER_VALUE(aHashEntry)) {
+        GetPrefValueFromEntry(aHashEntry, aPref, USER_VALUE);
+    } else {
+        aPref->userValue() = null_t();
+    }
 
-        case PREF_BOOL:
-            aTuple->boolVal = !!value->boolVal;
-            aTuple->type = PrefTuple::PREF_BOOL;
-            return;
-    }
+    MOZ_ASSERT(aPref->defaultValue().type() == dom::MaybePrefValue::Tnull_t ||
+               aPref->userValue().type() == dom::MaybePrefValue::Tnull_t ||
+               (aPref->defaultValue().get_PrefValue().type() ==
+                aPref->userValue().get_PrefValue().type()));
 }
 
 
 int
 pref_CompareStrings(const void *v1, const void *v2, void *unused)
 {
     char *s1 = *(char**) v1;
     char *s2 = *(char**) v2;
--- a/modules/libpref/src/prefapi_private_data.h
+++ b/modules/libpref/src/prefapi_private_data.h
@@ -3,31 +3,37 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 /* Data shared between prefapi.c and nsPref.cpp */
 
 extern PLDHashTable			gHashTable;
 extern bool                 gDirty;
 
-struct PrefTuple;
+namespace mozilla {
+namespace dom {
+class PrefSetting;
+}
+}
 
 enum pref_SaveTypes { SAVE_NONSHARED, SAVE_SHARED, SAVE_ALL, SAVE_ALL_AND_DEFAULTS };
 
 // Passed as the arg to pref_savePref
 struct pref_saveArgs {
   char **prefArray;
   pref_SaveTypes saveTypes;
 };
 
 PLDHashOperator
 pref_savePref(PLDHashTable *table, PLDHashEntryHdr *heh, uint32_t i, void *arg);
 
 PLDHashOperator
-pref_MirrorPrefs(PLDHashTable *table, PLDHashEntryHdr *heh, uint32_t i, void *arg);
+pref_GetPrefs(PLDHashTable *table,
+              PLDHashEntryHdr *heh, uint32_t i, void *arg);
 
 nsresult
-pref_SetPrefTuple(const PrefTuple &aPref,bool set_default = false);
+pref_SetPref(const mozilla::dom::PrefSetting& aPref);
 
 int pref_CompareStrings(const void *v1, const void *v2, void* unused);
 PrefHashEntry* pref_HashTableLookup(const void *key);
 
-void pref_GetTupleFromEntry(PrefHashEntry *aHashEntry, PrefTuple *aTuple);
+void pref_GetPrefFromEntry(PrefHashEntry *aHashEntry,
+                           mozilla::dom::PrefSetting* aPref);