Bug 1422163 - Make a new confirm dialog for clearing all site data that allows you to clear cache. r=Gijs draft
authorJohann Hofmann <jhofmann@mozilla.com>
Wed, 10 Jan 2018 12:24:40 +0100
changeset 723585 aa2187e181c981e1e3825edde33aceb8ba34a58c
parent 723009 5faab9e619901b1513fd4ca137747231be550def
child 723586 130a6ef553d5b0f13c59ed13480c03ec428f9a32
push id96475
push userjhofmann@mozilla.com
push dateTue, 23 Jan 2018 15:36:16 +0000
reviewersGijs
bugs1422163
milestone59.0a1
Bug 1422163 - Make a new confirm dialog for clearing all site data that allows you to clear cache. r=Gijs MozReview-Commit-ID: G9xQXlfT9Ay
browser/components/preferences/SiteDataManager.jsm
browser/components/preferences/clearSiteData.css
browser/components/preferences/clearSiteData.js
browser/components/preferences/clearSiteData.xul
browser/components/preferences/in-content/privacy.js
browser/components/preferences/jar.mn
browser/components/preferences/siteDataSettings.js
browser/locales/en-US/chrome/browser/preferences/clearSiteData.dtd
browser/locales/en-US/chrome/browser/preferences/clearSiteData.properties
browser/locales/en-US/chrome/browser/preferences/preferences.properties
browser/locales/en-US/chrome/browser/siteData.properties
browser/locales/jar.mn
--- a/browser/components/preferences/SiteDataManager.jsm
+++ b/browser/components/preferences/SiteDataManager.jsm
@@ -12,42 +12,90 @@ XPCOMUtils.defineLazyModuleGetter(this, 
 XPCOMUtils.defineLazyServiceGetter(this, "serviceWorkerManager",
                                    "@mozilla.org/serviceworkers/manager;1",
                                    "nsIServiceWorkerManager");
 
 this.EXPORTED_SYMBOLS = [
   "SiteDataManager"
 ];
 
+XPCOMUtils.defineLazyGetter(this, "gStringBundle", function() {
+  return Services.strings.createBundle("chrome://browser/locale/siteData.properties");
+});
+
 this.SiteDataManager = {
 
   _qms: Services.qms,
 
   _appCache: Cc["@mozilla.org/network/application-cache-service;1"].getService(Ci.nsIApplicationCacheService),
 
   // A Map of sites and their disk usage according to Quota Manager and appcache
   // Key is host (group sites based on host across scheme, port, origin atttributes).
   // Value is one object holding:
   //   - principals: instances of nsIPrincipal.
   //   - persisted: the persistent-storage status.
   //   - quotaUsage: the usage of indexedDB and localStorage.
   //   - appCacheList: an array of app cache; instances of nsIApplicationCache
   _sites: new Map(),
 
+  _getCacheSizeObserver: null,
+
+  _getCacheSizePromise: null,
+
   _getQuotaUsagePromise: null,
 
   _quotaUsageRequest: null,
 
   async updateSites() {
     Services.obs.notifyObservers(null, "sitedatamanager:updating-sites");
     await this._getQuotaUsage();
     this._updateAppCache();
     Services.obs.notifyObservers(null, "sitedatamanager:sites-updated");
   },
 
+  /**
+   * Retrieves the amount of space currently used by disk cache.
+   *
+   * You can use DownloadUtils.convertByteUnits to convert this to
+   * a user-understandable size/unit combination.
+   *
+   * @returns a Promise that resolves with the cache size on disk in bytes.
+   */
+  getCacheSize() {
+    if (this._getCacheSizePromise) {
+      return this._getCacheSizePromise;
+    }
+
+    this._getCacheSizePromise = new Promise((resolve, reject) => {
+      // Needs to root the observer since cache service keeps only a weak reference.
+      this._getCacheSizeObserver = {
+        onNetworkCacheDiskConsumption: consumption => {
+          resolve(consumption);
+          this._getCacheSizePromise = null;
+          this._getCacheSizeObserver = null;
+        },
+
+        QueryInterface: XPCOMUtils.generateQI([
+          Components.interfaces.nsICacheStorageConsumptionObserver,
+          Components.interfaces.nsISupportsWeakReference
+        ])
+      };
+
+      try {
+        Services.cache2.asyncGetDiskConsumption(this._getCacheSizeObserver);
+      } catch (e) {
+        reject(e);
+        this._getCacheSizePromise = null;
+        this._getCacheSizeObserver = null;
+      }
+    });
+
+    return this._getCacheSizePromise;
+  },
+
   _getQuotaUsage() {
     // Clear old data and requests first
     this._sites.clear();
     this._cancelGetQuotaUsage();
     this._getQuotaUsagePromise = new Promise(resolve => {
       let onUsageResult = request => {
         if (request.resultCode == Cr.NS_OK) {
           let items = request.result;
@@ -273,18 +321,66 @@ this.SiteDataManager = {
           })
           .then(() => this.updateSites());
     }
     if (unknownHost) {
       throw `SiteDataManager: removing unknown site of ${unknownHost}`;
     }
   },
 
+  /**
+   * In the specified window, shows a prompt for removing
+   * all site data, warning the user that this may log them
+   * out of websites.
+   *
+   * @param {mozIDOMWindowProxy} a parent DOM window to host the dialog.
+   * @returns a boolean whether the user confirmed the prompt.
+   */
+  promptSiteDataRemoval(win) {
+    let flags =
+      Services.prompt.BUTTON_TITLE_IS_STRING * Services.prompt.BUTTON_POS_0 +
+      Services.prompt.BUTTON_TITLE_CANCEL * Services.prompt.BUTTON_POS_1 +
+      Services.prompt.BUTTON_POS_0_DEFAULT;
+    let title = gStringBundle.GetStringFromName("clearSiteDataPromptTitle");
+    let text = gStringBundle.GetStringFromName("clearSiteDataPromptText");
+    let btn0Label = gStringBundle.GetStringFromName("clearSiteDataNow");
+
+    let result = Services.prompt.confirmEx(
+      win, title, text, flags, btn0Label, null, null, null, {});
+    return result == 0;
+  },
+
+  /**
+   * Clears all site data and cache
+   *
+   * @returns a Promise that resolves when the data is cleared.
+   */
   async removeAll() {
+    this.removeCache();
+    return this.removeSiteData();
+  },
+
+  /**
+   * Clears the entire network cache.
+   */
+  removeCache() {
     Services.cache2.clear();
+  },
+
+  /**
+   * Clears all site data, which currently means
+   *   - Cookies
+   *   - AppCache
+   *   - ServiceWorkers
+   *   - Quota Managed Storage
+   *   - persistent-storage permissions
+   *
+   * @returns a Promise that resolves with the cache size on disk in bytes
+   */
+  async removeSiteData() {
     Services.cookies.removeAll();
     OfflineAppCacheHelper.clear();
 
     // Iterate through the service workers and remove them.
     let promises = [];
     let serviceWorkers = serviceWorkerManager.getAllRegistrations();
     for (let i = 0; i < serviceWorkers.length; i++) {
       let sw = serviceWorkers.queryElementAt(i, Ci.nsIServiceWorkerRegistrationInfo);
new file mode 100644
--- /dev/null
+++ b/browser/components/preferences/clearSiteData.css
@@ -0,0 +1,19 @@
+/* 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/. */
+
+.options-container {
+  background-color: var(--in-content-box-background);
+  border: 1px solid var(--in-content-box-border-color);
+  border-radius: 2px;
+  color: var(--in-content-text-color);
+  padding: 0.5em;
+}
+
+.option {
+  padding-bottom: 16px;
+}
+
+.option-description {
+  color: #737373;
+}
new file mode 100644
--- /dev/null
+++ b/browser/components/preferences/clearSiteData.js
@@ -0,0 +1,86 @@
+/* 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/. */
+
+Components.utils.import("resource://gre/modules/Services.jsm");
+Components.utils.import("resource://gre/modules/AppConstants.jsm");
+Components.utils.import("resource://gre/modules/DownloadUtils.jsm");
+Components.utils.import("resource:///modules/SiteDataManager.jsm");
+
+var gClearSiteDataDialog = {
+  _clearSiteDataCheckbox: null,
+  _clearCacheCheckbox: null,
+  _clearButton: null,
+
+  init() {
+    this._bundle = Services.strings
+      .createBundle("chrome://browser/locale/preferences/clearSiteData.properties");
+
+    SiteDataManager.getTotalUsage().then(bytes => {
+      // Size is an array of amount and unit, e.g. [20, "MB"].
+      let size = DownloadUtils.convertByteUnits(bytes);
+      document.getElementById("clearSiteDataLabel").value =
+        this._bundle.formatStringFromName("clearSiteDataWithEstimates.label", size, 2);
+    });
+    SiteDataManager.getCacheSize().then(bytes => {
+      // Size is an array of amount and unit, e.g. [20, "MB"].
+      let size = DownloadUtils.convertByteUnits(bytes);
+      document.getElementById("clearCacheLabel").value =
+        this._bundle.formatStringFromName("clearCacheWithEstimates.label", size, 2);
+    });
+
+    this._clearButton = document.getElementById("clearButton");
+    this._cancelButton = document.getElementById("cancelButton");
+    this._clearSiteDataCheckbox = document.getElementById("clearSiteData");
+    this._clearCacheCheckbox = document.getElementById("clearCache");
+
+    window.addEventListener("unload", () => this.uninit());
+    window.addEventListener("keypress", this.onWindowKeyPress);
+
+    this._cancelButton.addEventListener("command", window.close);
+    this._clearButton.addEventListener("command", () => this.onClear());
+
+    this._clearSiteDataCheckbox.addEventListener("command", e => this.onCheckboxCommand(e));
+    this._clearCacheCheckbox.addEventListener("command", e => this.onCheckboxCommand(e));
+  },
+
+  onWindowKeyPress(event) {
+    if (event.keyCode == KeyEvent.DOM_VK_ESCAPE)
+      window.close();
+  },
+
+  onCheckboxCommand(event) {
+    this._clearButton.disabled =
+      !(this._clearSiteDataCheckbox.checked || this._clearCacheCheckbox.checked);
+  },
+
+  onClear() {
+    let allowed = true;
+
+    if (this._clearSiteDataCheckbox.checked) {
+      allowed = SiteDataManager.promptSiteDataRemoval(window);
+      if (allowed) {
+        SiteDataManager.removeSiteData();
+      }
+    }
+
+    if (this._clearCacheCheckbox.checked && allowed) {
+      SiteDataManager.removeCache();
+      // Update cache UI in the likely case that about:preferences opened this window.
+      if (window.opener.gPrivacyPane) {
+        window.opener.gPrivacyPane.updateActualCacheSize();
+      }
+    }
+
+    if (allowed) {
+      window.close();
+    }
+  },
+
+  uninit() {
+    this._clearSiteDataCheckbox.removeEventListener("command", this);
+    this._clearCacheCheckbox.removeEventListener("command", this);
+  },
+};
+
+window.addEventListener("load", () => gClearSiteDataDialog.init());
new file mode 100644
--- /dev/null
+++ b/browser/components/preferences/clearSiteData.xul
@@ -0,0 +1,59 @@
+<?xml version="1.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/. -->
+
+<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
+<?xml-stylesheet href="chrome://browser/skin/preferences/preferences.css" type="text/css"?>
+<?xml-stylesheet href="chrome://browser/content/preferences/clearSiteData.css" type="text/css"?>
+
+<!DOCTYPE dialog SYSTEM "chrome://browser/locale/preferences/clearSiteData.dtd" >
+
+<window id="ClearSiteDataDialog" class="windowDialog"
+        windowtype="Browser:ClearSiteData"
+        xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+        style="width: &window.width;;"
+        title="&window.title;"
+        persist="screenX screenY width height">
+
+  <script src="chrome://browser/content/preferences/clearSiteData.js"/>
+
+  <stringbundle id="bundlePreferences"
+                src="chrome://browser/locale/preferences/preferences.properties"/>
+
+  <keyset>
+    <key key="&windowClose.key;" modifiers="accel" oncommand="window.close();"/>
+  </keyset>
+
+  <vbox class="contentPane largeDialogContainer" flex="1">
+    <description control="url">&window.description;</description>
+    <separator class="thin"/>
+    <vbox class="options-container">
+      <hbox class="option">
+        <checkbox id="clearSiteData" checked="true"
+                  accesskey="&clearSiteData.accesskey;" />
+        <vbox>
+          <label for="clearSiteData" id="clearSiteDataLabel" value="&clearSiteData.label;" />
+          <description class="option-description">&clearSiteData.description;</description>
+        </vbox>
+      </hbox>
+      <hbox class="option">
+        <checkbox id="clearCache" checked="true"
+                  accesskey="&clearCache.accesskey;" />
+        <vbox>
+          <label for="clearCache" id="clearCacheLabel" value="&clearCache.label;" />
+          <description class="option-description">&clearCache.description;</description>
+        </vbox>
+      </hbox>
+    </vbox>
+  </vbox>
+  <vbox>
+    <hbox class="actionButtons" align="right" flex="1">
+      <button id="cancelButton" icon="close"
+              label="&button.cancel.label;" accesskey="&button.cancel.accesskey;" />
+      <button id="clearButton" icon="save"
+              label="&button.clear.label;" accesskey="&button.clear.accesskey;"/>
+    </hbox>
+  </vbox>
+</window>
--- a/browser/components/preferences/in-content/privacy.js
+++ b/browser/components/preferences/in-content/privacy.js
@@ -1512,30 +1512,17 @@ var gPrivacyPane = {
     let cacheSizeElem = document.getElementById("cacheSize");
     let cachePref = Preferences.get("browser.cache.disk.capacity");
     // Converts the cache size as specified in UI (in MB) to KB.
     let intValue = parseInt(cacheSizeElem.value, 10);
     cachePref.value = isNaN(intValue) ? 0 : intValue * 1024;
   },
 
   clearSiteData() {
-    let flags =
-      Services.prompt.BUTTON_TITLE_IS_STRING * Services.prompt.BUTTON_POS_0 +
-      Services.prompt.BUTTON_TITLE_CANCEL * Services.prompt.BUTTON_POS_1 +
-      Services.prompt.BUTTON_POS_0_DEFAULT;
-    let prefStrBundle = document.getElementById("bundlePreferences");
-    let title = prefStrBundle.getString("clearSiteDataPromptTitle");
-    let text = prefStrBundle.getString("clearSiteDataPromptText");
-    let btn0Label = prefStrBundle.getString("clearSiteDataNow");
-
-    let result = Services.prompt.confirmEx(
-      window, title, text, flags, btn0Label, null, null, null, {});
-    if (result == 0) {
-      SiteDataManager.removeAll();
-    }
+    gSubDialog.open("chrome://browser/content/preferences/clearSiteData.xul");
   },
 
   initDataCollection() {
     this._setupLearnMoreLink("toolkit.datacollection.infoURL",
       "dataCollectionPrivacyNotice");
   },
 
   initSubmitCrashes() {
--- a/browser/components/preferences/jar.mn
+++ b/browser/components/preferences/jar.mn
@@ -2,16 +2,19 @@
 # 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/.
 
 browser.jar:
     content/browser/preferences/applicationManager.xul
     content/browser/preferences/applicationManager.js
     content/browser/preferences/blocklists.xul
     content/browser/preferences/blocklists.js
+    content/browser/preferences/clearSiteData.css
+    content/browser/preferences/clearSiteData.js
+    content/browser/preferences/clearSiteData.xul
 *   content/browser/preferences/colors.xul
     content/browser/preferences/colors.js
 *   content/browser/preferences/cookies.xul
     content/browser/preferences/cookies.js
 *   content/browser/preferences/connection.xul
     content/browser/preferences/connection.js
     content/browser/preferences/fonts.xul
     content/browser/preferences/fonts.js
--- a/browser/components/preferences/siteDataSettings.js
+++ b/browser/components/preferences/siteDataSettings.js
@@ -203,28 +203,17 @@ let gSiteDataSettings = {
         removals.add(site.host);
         return false;
       }
       return true;
     });
 
     if (removals.size > 0) {
       if (this._sites.length == 0) {
-        // User selects all sites so equivalent to clearing all data
-        let flags =
-          Services.prompt.BUTTON_TITLE_IS_STRING * Services.prompt.BUTTON_POS_0 +
-          Services.prompt.BUTTON_TITLE_CANCEL * Services.prompt.BUTTON_POS_1 +
-          Services.prompt.BUTTON_POS_0_DEFAULT;
-        let prefStrBundle = document.getElementById("bundlePreferences");
-        let title = prefStrBundle.getString("clearSiteDataPromptTitle");
-        let text = prefStrBundle.getString("clearSiteDataPromptText");
-        let btn0Label = prefStrBundle.getString("clearSiteDataNow");
-        let result = Services.prompt.confirmEx(window, title, text, flags, btn0Label, null, null, null, {});
-        allowed = result == 0;
-        if (allowed) {
+        if (SiteDataManager.promptSiteDataRemoval(window)) {
           SiteDataManager.removeAll();
         }
       } else {
         // User only removes partial sites.
         // We will remove cookies based on base domain, say, user selects "news.foo.com" to remove.
         // The cookies under "music.foo.com" will be removed together.
         // We have to prompt user about this action.
         let hostsTable = new Map();
new file mode 100644
--- /dev/null
+++ b/browser/locales/en-US/chrome/browser/preferences/clearSiteData.dtd
@@ -0,0 +1,22 @@
+<!-- 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/. -->
+
+<!ENTITY window.title                 "Clear Data">
+<!ENTITY window.width                 "35em">
+
+<!ENTITY window.description           "Clearing all cookies and site data stored by Firefox may sign you out of websites and remove offline web content. Clearing cache data will not affect your logins.">
+<!ENTITY windowClose.key              "w">
+
+<!ENTITY clearSiteData.label          "Cookies and Site Data">
+<!ENTITY clearSiteData.accesskey      "S">
+<!ENTITY clearSiteData.description    "You may get signed out of websites if cleared">
+
+<!ENTITY clearCache.label             "Cached Web Content">
+<!ENTITY clearCache.accesskey         "W">
+<!ENTITY clearCache.description       "Will require websites to reload images and data">
+
+<!ENTITY button.cancel.label          "Cancel">
+<!ENTITY button.cancel.accesskey      "C">
+<!ENTITY button.clear.label           "Clear">
+<!ENTITY button.clear.accesskey       "l">
new file mode 100644
--- /dev/null
+++ b/browser/locales/en-US/chrome/browser/preferences/clearSiteData.properties
@@ -0,0 +1,7 @@
+# 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/.
+
+clearSiteDataWithEstimates.label = Site Data and Cookies (%1$S %2$S)
+clearCacheWithEstimates.label = Cached Web Content (%1$S %2$S)
+
--- a/browser/locales/en-US/chrome/browser/preferences/preferences.properties
+++ b/browser/locales/en-US/chrome/browser/preferences/preferences.properties
@@ -183,19 +183,16 @@ actualAppCacheSize=Your application cach
 
 ####Preferences::Advanced::Network
 #LOCALIZATION NOTE: The next string is for the total usage of site data.
 #   e.g., "The total usage is currently using 200 MB"
 #   %1$S = size
 #   %2$S = unit (MB, KB, etc.)
 totalSiteDataSize=Your stored site data is currently using %1$S %2$S of disk space
 loadingSiteDataSize=Calculating site data size…
-clearSiteDataPromptTitle=Clear all cookies and site data
-clearSiteDataPromptText=Selecting ‘Clear Now’ will clear all cookies and site data stored by Firefox. This may sign you out of websites and remove offline web content.
-clearSiteDataNow=Clear Now
 persistent=Persistent
 siteUsage=%1$S %2$S
 acceptRemove=Remove
 # LOCALIZATION NOTE (siteDataSettings2.description): %S = brandShortName
 siteDataSettings2.description=The following websites store site data on your computer. %S keeps data from websites with persistent storage until you delete it, and deletes data from websites with non-persistent storage as space is needed.
 # LOCALIZATION NOTE (removeAllSiteData, removeAllSiteDataShown):
 # removeAllSiteData and removeAllSiteDataShown are both used on the same one button,
 # never displayed together and can share the same accesskey.
new file mode 100644
--- /dev/null
+++ b/browser/locales/en-US/chrome/browser/siteData.properties
@@ -0,0 +1,7 @@
+# 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/.
+
+clearSiteDataPromptTitle=Clear all cookies and site data
+clearSiteDataPromptText=Selecting ‘Clear Now’ will clear all cookies and site data stored by Firefox. This may sign you out of websites and remove offline web content.
+clearSiteDataNow=Clear Now
--- a/browser/locales/jar.mn
+++ b/browser/locales/jar.mn
@@ -33,16 +33,17 @@
     locale/browser/newTab.dtd                      (%chrome/browser/newTab.dtd)
     locale/browser/newTab.properties               (%chrome/browser/newTab.properties)
     locale/browser/pageInfo.dtd                    (%chrome/browser/pageInfo.dtd)
     locale/browser/pageInfo.properties             (%chrome/browser/pageInfo.properties)
     locale/browser/quitDialog.properties           (%chrome/browser/quitDialog.properties)
     locale/browser/safeMode.dtd                    (%chrome/browser/safeMode.dtd)
     locale/browser/sanitize.dtd                    (%chrome/browser/sanitize.dtd)
     locale/browser/search.properties               (%chrome/browser/search.properties)
+    locale/browser/siteData.properties             (%chrome/browser/siteData.properties)
     locale/browser/sitePermissions.properties      (%chrome/browser/sitePermissions.properties)
     locale/browser/engineManager.properties        (%chrome/browser/engineManager.properties)
     locale/browser/setDesktopBackground.dtd        (%chrome/browser/setDesktopBackground.dtd)
     locale/browser/shellservice.properties         (%chrome/browser/shellservice.properties)
     locale/browser/tabbrowser.properties           (%chrome/browser/tabbrowser.properties)
     locale/browser/taskbar.properties              (%chrome/browser/taskbar.properties)
     locale/browser/translation.dtd                 (%chrome/browser/translation.dtd)
     locale/browser/translation.properties          (%chrome/browser/translation.properties)
@@ -61,16 +62,18 @@
     locale/browser/feeds/subscribe.properties       (%chrome/browser/feeds/subscribe.properties)
     locale/browser/migration/migration.dtd         (%chrome/browser/migration/migration.dtd)
     locale/browser/migration/migration.properties  (%chrome/browser/migration/migration.properties)
     locale/browser/preferences/advanced.dtd           (%chrome/browser/preferences/advanced.dtd)
     locale/browser/preferences/applicationManager.dtd     (%chrome/browser/preferences/applicationManager.dtd)
     locale/browser/preferences/applicationManager.properties     (%chrome/browser/preferences/applicationManager.properties)
     locale/browser/preferences/applications.dtd       (%chrome/browser/preferences/applications.dtd)
     locale/browser/preferences/blocklists.dtd         (%chrome/browser/preferences/blocklists.dtd)
+    locale/browser/preferences/clearSiteData.dtd      (%chrome/browser/preferences/clearSiteData.dtd)
+    locale/browser/preferences/clearSiteData.properties     (%chrome/browser/preferences/clearSiteData.properties)
     locale/browser/preferences/colors.dtd             (%chrome/browser/preferences/colors.dtd)
     locale/browser/preferences/connection.dtd         (%chrome/browser/preferences/connection.dtd)
     locale/browser/preferences/containers.dtd         (%chrome/browser/preferences/containers.dtd)
     locale/browser/preferences/containers.properties     (%chrome/browser/preferences/containers.properties)
     locale/browser/preferences/content.dtd            (%chrome/browser/preferences/content.dtd)
     locale/browser/preferences/cookies.dtd            (%chrome/browser/preferences/cookies.dtd)
     locale/browser/preferences/fonts.dtd              (%chrome/browser/preferences/fonts.dtd)
     locale/browser/preferences/languages.dtd          (%chrome/browser/preferences/languages.dtd)