Bug 591780 - Frontend support for restartless dictionaries. r=ehsan, r=Mossop
authorJesper Kristensen <mail@jesperkristensen.dk>
Thu, 06 Oct 2011 12:06:18 -0700
changeset 79614 6f4259bdadf5ddc8b09fcbdabc745e85ad2c89ae
parent 79613 e390059dce9926b81c23c57283758dff590b49c9
child 79615 73aa318342973d4d427e4774e470fc49f2773b28
push id434
push userclegnitto@mozilla.com
push dateWed, 21 Dec 2011 12:10:54 +0000
treeherdermozilla-beta@bddb6ed8dd47 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersehsan, Mossop
bugs591780
milestone10.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 591780 - Frontend support for restartless dictionaries. r=ehsan, r=Mossop
extensions/spellcheck/hunspell/src/mozHunspell.cpp
toolkit/locales/en-US/chrome/mozapps/extensions/extensions.properties
toolkit/mozapps/extensions/AddonRepository.jsm
toolkit/mozapps/extensions/Makefile.in
toolkit/mozapps/extensions/SpellCheckDictionaryBootstrap.js
toolkit/mozapps/extensions/XPIProvider.jsm
toolkit/mozapps/extensions/nsBlocklistService.js
toolkit/mozapps/extensions/test/addons/test_dictionary/dictionaries/ab-CD.dic
toolkit/mozapps/extensions/test/addons/test_dictionary/install.rdf
toolkit/mozapps/extensions/test/addons/test_dictionary_2/dictionaries/ab-CD.dic
toolkit/mozapps/extensions/test/addons/test_dictionary_2/install.rdf
toolkit/mozapps/extensions/test/xpcshell/test_dictionary.js
toolkit/mozapps/extensions/test/xpcshell/xpcshell.ini
toolkit/themes/gnomestripe/mozapps/extensions/category-dictionaries.png
toolkit/themes/gnomestripe/mozapps/extensions/dictionaryGeneric-16.png
toolkit/themes/gnomestripe/mozapps/extensions/dictionaryGeneric.png
toolkit/themes/gnomestripe/mozapps/extensions/extensions.css
toolkit/themes/gnomestripe/mozapps/extensions/newaddon.css
toolkit/themes/gnomestripe/mozapps/extensions/selectAddons.css
toolkit/themes/gnomestripe/mozapps/jar.mn
toolkit/themes/pinstripe/mozapps/extensions/about.css
toolkit/themes/pinstripe/mozapps/extensions/category-dictionaries.png
toolkit/themes/pinstripe/mozapps/extensions/dictionaryGeneric-16.png
toolkit/themes/pinstripe/mozapps/extensions/dictionaryGeneric.png
toolkit/themes/pinstripe/mozapps/extensions/eula.css
toolkit/themes/pinstripe/mozapps/extensions/extensions.css
toolkit/themes/pinstripe/mozapps/extensions/newaddon.css
toolkit/themes/pinstripe/mozapps/extensions/selectAddons.css
toolkit/themes/pinstripe/mozapps/jar.mn
toolkit/themes/pinstripe/mozapps/xpinstall/xpinstallConfirm.css
toolkit/themes/winstripe/mozapps/extensions/about.css
toolkit/themes/winstripe/mozapps/extensions/category-dictionaries-aero.png
toolkit/themes/winstripe/mozapps/extensions/category-dictionaries.png
toolkit/themes/winstripe/mozapps/extensions/dictionaryGeneric-16-aero.png
toolkit/themes/winstripe/mozapps/extensions/dictionaryGeneric-16.png
toolkit/themes/winstripe/mozapps/extensions/dictionaryGeneric-aero.png
toolkit/themes/winstripe/mozapps/extensions/dictionaryGeneric.png
toolkit/themes/winstripe/mozapps/extensions/eula.css
toolkit/themes/winstripe/mozapps/extensions/extensions.css
toolkit/themes/winstripe/mozapps/extensions/newaddon.css
toolkit/themes/winstripe/mozapps/extensions/selectAddons.css
toolkit/themes/winstripe/mozapps/jar.mn
toolkit/themes/winstripe/mozapps/xpinstall/xpinstallConfirm.css
--- a/extensions/spellcheck/hunspell/src/mozHunspell.cpp
+++ b/extensions/spellcheck/hunspell/src/mozHunspell.cpp
@@ -123,16 +123,17 @@ mozHunspell::Init()
   if (!mDictionaries.Init())
     return NS_ERROR_OUT_OF_MEMORY;
 
   LoadDictionaryList();
 
   nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
   if (obs) {
     obs->AddObserver(this, "profile-do-change", PR_TRUE);
+    obs->AddObserver(this, "profile-after-change", PR_TRUE);
   }
 
   mHunspellReporter = new NS_MEMORY_REPORTER_NAME(Hunspell);
   NS_RegisterMemoryReporter(mHunspellReporter);
 
   return NS_OK;
 }
 
@@ -588,17 +589,18 @@ NS_IMETHODIMP mozHunspell::Suggest(const
   NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(*aSuggestionCount, wlst);
   return rv;
 }
 
 NS_IMETHODIMP
 mozHunspell::Observe(nsISupports* aSubj, const char *aTopic,
                     const PRUnichar *aData)
 {
-  NS_ASSERTION(!strcmp(aTopic, "profile-do-change"),
+  NS_ASSERTION(!strcmp(aTopic, "profile-do-change")
+               || !strcmp(aTopic, "profile-after-change"),
                "Unexpected observer topic");
 
   LoadDictionaryList();
 
   return NS_OK;
 }
 
 /* void addDirectory(in nsIFile dir); */
--- a/toolkit/locales/en-US/chrome/mozapps/extensions/extensions.properties
+++ b/toolkit/locales/en-US/chrome/mozapps/extensions/extensions.properties
@@ -104,8 +104,9 @@ cmd.purchaseAddon.accesskey=u
 
 #LOCALIZATION NOTE (eulaHeader) %S is name of the add-on asking the user to agree to the EULA
 eulaHeader=%S requires that you accept the following End User License Agreement before installation can proceed:
 
 type.extension.name=Extensions
 type.theme.name=Appearance
 type.locale.name=Languages
 type.plugin.name=Plugins
+type.dictionary.name=Dictionaries
--- a/toolkit/mozapps/extensions/AddonRepository.jsm
+++ b/toolkit/mozapps/extensions/AddonRepository.jsm
@@ -58,17 +58,17 @@ const PREF_GETADDONS_BYIDS              
 const PREF_GETADDONS_BROWSERECOMMENDED   = "extensions.getAddons.recommended.browseURL";
 const PREF_GETADDONS_GETRECOMMENDED      = "extensions.getAddons.recommended.url";
 const PREF_GETADDONS_BROWSESEARCHRESULTS = "extensions.getAddons.search.browseURL";
 const PREF_GETADDONS_GETSEARCHRESULTS    = "extensions.getAddons.search.url";
 
 const XMLURI_PARSE_ERROR  = "http://www.mozilla.org/newlayout/xml/parsererror.xml";
 
 const API_VERSION = "1.5";
-const DEFAULT_CACHE_TYPES = "extension,theme,locale";
+const DEFAULT_CACHE_TYPES = "extension,theme,locale,dictionary";
 
 const KEY_PROFILEDIR = "ProfD";
 const FILE_DATABASE  = "addons.sqlite";
 const DB_SCHEMA      = 2;
 
 ["LOG", "WARN", "ERROR"].forEach(function(aName) {
   this.__defineGetter__(aName, function() {
     Components.utils.import("resource://gre/modules/AddonLogging.jsm");
@@ -928,16 +928,19 @@ var AddonRepository = {
           let id = parseInt(node.getAttribute("id"));
           switch (id) {
             case 1:
               addon.type = "extension";
               break;
             case 2:
               addon.type = "theme";
               break;
+            case 3:
+              addon.type = "dictionary";
+              break;
             default:
               WARN("Unknown type id when parsing addon: " + id);
           }
           break;
         case "authors":
           let authorNodes = node.getElementsByTagName("author");
           Array.forEach(authorNodes, function(aAuthorNode) {
             let name = self._getDescendantTextContent(aAuthorNode, "name");
--- a/toolkit/mozapps/extensions/Makefile.in
+++ b/toolkit/mozapps/extensions/Makefile.in
@@ -67,16 +67,17 @@ EXTRA_PP_JS_MODULES = \
   AddonRepository.jsm \
   AddonUpdateChecker.jsm \
   PluginProvider.jsm \
   XPIProvider.jsm \
   $(NULL)
 
 EXTRA_JS_MODULES = \
   LightweightThemeManager.jsm \
+  SpellCheckDictionaryBootstrap.js \
   $(NULL)
 
 ifdef ENABLE_TESTS
 DIRS += test
 endif
 
 EXTRA_DSO_LDOPTS = \
   $(MOZ_JS_LIBS) \
new file mode 100644
--- /dev/null
+++ b/toolkit/mozapps/extensions/SpellCheckDictionaryBootstrap.js
@@ -0,0 +1,49 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is the Extension Manager.
+ *
+ * The Initial Developer of the Original Code is
+ * Jesper Kristensen <mail@jesperkristensen.dk>.
+ * Portions created by the Initial Developer are Copyright (C) 2011
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+var hunspell, dir;
+
+function startup(data) {
+  hunspell = Components.classes["@mozilla.org/spellchecker/engine;1"]
+                       .getService(Components.interfaces.mozISpellCheckingEngine);
+  dir = data.installPath.clone();
+  dir.append("dictionaries");
+  hunspell.addDirectory(dir);
+}
+
+function shutdown() {
+  hunspell.removeDirectory(dir);
+}
--- a/toolkit/mozapps/extensions/XPIProvider.jsm
+++ b/toolkit/mozapps/extensions/XPIProvider.jsm
@@ -159,17 +159,18 @@ const BOOTSTRAP_REASONS = {
   ADDON_DOWNGRADE : 8
 };
 
 // Map new string type identifiers to old style nsIUpdateItem types
 const TYPES = {
   extension: 2,
   theme: 4,
   locale: 8,
-  multipackage: 32
+  multipackage: 32,
+  dictionary: 64
 };
 
 const MSG_JAR_FLUSH = "AddonJarFlush";
 
 /**
  * Valid IDs fit this pattern.
  */
 var gIDTest = /^(\{[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\}|[a-z0-9-\._]*\@[a-z0-9-\._]+)$/i;
@@ -707,16 +708,20 @@ function loadManifestFromRDF(aUri, aStre
     if (addon.optionsType &&
         addon.optionsType != AddonManager.OPTIONS_TYPE_DIALOG &&
         addon.optionsType != AddonManager.OPTIONS_TYPE_INLINE &&
         addon.optionsType != AddonManager.OPTIONS_TYPE_TAB) {
       throw new Error("Install manifest specifies unknown type: " + addon.optionsType);
     }
   }
   else {
+    // spell check dictionaries never require a restart
+    if (addon.type == "dictionary")
+      addon.bootstrap = true;
+
     // Only extensions are allowed to provide an optionsURL, optionsType or aboutURL. For
     // all other types they are silently ignored
     addon.optionsURL = null;
     addon.optionsType = null;
     addon.aboutURL = null;
 
     if (addon.type == "theme") {
       if (!addon.internalName)
@@ -1616,31 +1621,32 @@ var XPIProvider = {
                                              this.checkCompatibility);
       } catch (e) { }
       this.addAddonsToCrashReporter();
     }
 
     for (let id in this.bootstrappedAddons) {
       let file = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsILocalFile);
       file.persistentDescriptor = this.bootstrappedAddons[id].descriptor;
-      this.callBootstrapMethod(id, this.bootstrappedAddons[id].version, file,
+      this.callBootstrapMethod(id, this.bootstrappedAddons[id].version,
+                               this.bootstrappedAddons[id].type, file,
                                "startup", BOOTSTRAP_REASONS.APP_STARTUP);
     }
 
     // Let these shutdown a little earlier when they still have access to most
     // of XPCOM
     Services.obs.addObserver({
       observe: function(aSubject, aTopic, aData) {
         Services.prefs.setCharPref(PREF_BOOTSTRAP_ADDONS,
                                    JSON.stringify(XPIProvider.bootstrappedAddons));
         for (let id in XPIProvider.bootstrappedAddons) {
           let file = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsILocalFile);
           file.persistentDescriptor = XPIProvider.bootstrappedAddons[id].descriptor;
           XPIProvider.callBootstrapMethod(id, XPIProvider.bootstrappedAddons[id].version,
-                                          file, "shutdown",
+                                          XPIProvider.bootstrappedAddons[id].type, file, "shutdown",
                                           BOOTSTRAP_REASONS.APP_SHUTDOWN);
         }
         Services.obs.removeObserver(this, "quit-application-granted");
       }
     }, "quit-application-granted", false);
 
     this.extensionsActive = true;
   },
@@ -2026,17 +2032,17 @@ var XPIProvider = {
               // call its uninstall method
               let oldVersion = aManifests[aLocation.name][id].version;
               let newVersion = oldBootstrap.version;
               let uninstallReason = Services.vc.compare(newVersion, oldVersion) < 0 ?
                                     BOOTSTRAP_REASONS.ADDON_UPGRADE :
                                     BOOTSTRAP_REASONS.ADDON_DOWNGRADE;
 
               this.callBootstrapMethod(existingAddonID, oldBootstrap.version,
-                                       existingAddon, "uninstall", uninstallReason);
+                                       oldBootstrap.type, existingAddon, "uninstall", uninstallReason);
               this.unloadBootstrapScope(existingAddonID);
               flushStartupCache();
             }
           }
           catch (e) {
           }
         }
 
@@ -2055,17 +2061,17 @@ var XPIProvider = {
           // Make sure not to delete the cached manifest json file
           seenFiles.pop();
 
           delete aManifests[aLocation.name][id];
 
           if (oldBootstrap) {
             // Re-install the old add-on
             this.callBootstrapMethod(existingAddonID, oldBootstrap.version,
-                                     existingAddon, "install",
+                                     oldBootstrap.type, existingAddon, "install",
                                      BOOTSTRAP_REASONS.ADDON_INSTALL);
           }
           continue;
         }
       }
       entries.close();
 
       try {
@@ -2317,17 +2323,17 @@ var XPIProvider = {
           flushStartupCache();
 
           let installReason = Services.vc.compare(aOldAddon.version, newAddon.version) < 0 ?
                               BOOTSTRAP_REASONS.ADDON_UPGRADE :
                               BOOTSTRAP_REASONS.ADDON_DOWNGRADE;
 
           let file = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsILocalFile);
           file.persistentDescriptor = aAddonState.descriptor;
-          XPIProvider.callBootstrapMethod(newAddon.id, newAddon.version, file,
+          XPIProvider.callBootstrapMethod(newAddon.id, newAddon.version, newAddon.type, file,
                                           "install", installReason);
           return false;
         }
 
         return true;
       }
 
       return false;
@@ -2393,17 +2399,17 @@ var XPIProvider = {
           AddonManagerPrivate.addStartupChange(AddonManager.STARTUP_CHANGE_CHANGED,
                                                aOldAddon.id);
           XPIDatabase.makeAddonVisible(aOldAddon);
 
           if (aOldAddon.bootstrap) {
             // The add-on is bootstrappable so call its install script
             let file = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsILocalFile);
             file.persistentDescriptor = aAddonState.descriptor;
-            XPIProvider.callBootstrapMethod(aOldAddon.id, aOldAddon.version, file,
+            XPIProvider.callBootstrapMethod(aOldAddon.id, aOldAddon.version, aOldAddon.type, file,
                                             "install",
                                             BOOTSTRAP_REASONS.ADDON_INSTALL);
 
             // If it should be active then mark it as active otherwise unload
             // its scope
             if (!isAddonDisabled(aOldAddon)) {
               aOldAddon.active = true;
               XPIDatabase.updateAddonActive(aOldAddon);
@@ -2471,16 +2477,17 @@ var XPIProvider = {
             changed = true;
           }
         }
       }
 
       if (aOldAddon.visible && aOldAddon.active && aOldAddon.bootstrap) {
         XPIProvider.bootstrappedAddons[aOldAddon.id] = {
           version: aOldAddon.version,
+          type: aOldAddon.type,
           descriptor: aAddonState.descriptor
         };
       }
 
       return changed;
     }
 
     /**
@@ -2677,33 +2684,33 @@ var XPIProvider = {
                           BOOTSTRAP_REASONS.ADDON_UPGRADE :
                           BOOTSTRAP_REASONS.ADDON_DOWNGRADE;
 
           let oldAddonFile = Cc["@mozilla.org/file/local;1"].
                              createInstance(Ci.nsILocalFile);
           oldAddonFile.persistentDescriptor = oldBootstrap.descriptor;
 
           XPIProvider.callBootstrapMethod(newAddon.id, oldBootstrap.version,
-                                          oldAddonFile, "uninstall",
+                                          oldBootstrap.type, oldAddonFile, "uninstall",
                                           installReason);
           XPIProvider.unloadBootstrapScope(newAddon.id);
 
           // If the new add-on is bootstrapped then we must flush the caches
           // before calling the new bootstrap script
           if (newAddon.bootstrap)
             flushStartupCache();
         }
 
         if (!newAddon.bootstrap)
           return true;
 
         // Visible bootstrapped add-ons need to have their install method called
         let file = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsILocalFile);
         file.persistentDescriptor = aAddonState.descriptor;
-        XPIProvider.callBootstrapMethod(newAddon.id, newAddon.version, file,
+        XPIProvider.callBootstrapMethod(newAddon.id, newAddon.version, newAddon.type, file,
                                         "install", installReason);
         if (!newAddon.active)
           XPIProvider.unloadBootstrapScope(newAddon.id);
       }
 
       return false;
     }
 
@@ -3445,21 +3452,22 @@ var XPIProvider = {
    * @param  aId
    *         The add-on's ID
    * @param  aFile
    *         The nsILocalFile for the add-on
    * @param  aVersion
    *         The add-on's version
    * @return a JavaScript scope
    */
-  loadBootstrapScope: function XPI_loadBootstrapScope(aId, aFile, aVersion) {
+  loadBootstrapScope: function XPI_loadBootstrapScope(aId, aFile, aVersion, aType) {
     LOG("Loading bootstrap scope from " + aFile.path);
     // Mark the add-on as active for the crash reporter before loading
     this.bootstrappedAddons[aId] = {
       version: aVersion,
+      type: aType,
       descriptor: aFile.persistentDescriptor
     };
     this.addAddonsToCrashReporter();
 
     let principal = Cc["@mozilla.org/systemprincipal;1"].
                     createInstance(Ci.nsIPrincipal);
 
     if (!aFile.exists()) {
@@ -3475,17 +3483,22 @@ var XPIProvider = {
 
     let loader = Cc["@mozilla.org/moz/jssubscript-loader;1"].
                  createInstance(Ci.mozIJSSubScriptLoader);
 
     try {
       // As we don't want our caller to control the JS version used for the
       // bootstrap file, we run loadSubScript within the context of the
       // sandbox with the latest JS version set explicitly.
-      this.bootstrapScopes[aId].__SCRIPT_URI_SPEC__ = uri;
+      if (aType == "dictionary") {
+        this.bootstrapScopes[aId].__SCRIPT_URI_SPEC__ =
+            "resource://gre/modules/SpellCheckDictionaryBootstrap.js"
+      } else {
+        this.bootstrapScopes[aId].__SCRIPT_URI_SPEC__ = uri;
+      }
       Components.utils.evalInSandbox(
         "Components.classes['@mozilla.org/moz/jssubscript-loader;1'] \
                    .createInstance(Components.interfaces.mozIJSSubScriptLoader) \
                    .loadSubScript(__SCRIPT_URI_SPEC__);", this.bootstrapScopes[aId], "ECMAv5");
     }
     catch (e) {
       WARN("Error loading bootstrap.js for " + aId, e);
     }
@@ -3510,32 +3523,34 @@ var XPIProvider = {
 
   /**
    * Calls a bootstrap method for an add-on.
    *
    * @param  aId
    *         The ID of the add-on
    * @param  aVersion
    *         The version of the add-on
+   * @param  aType
+   *         The type for the add-on
    * @param  aFile
    *         The nsILocalFile for the add-on
    * @param  aMethod
    *         The name of the bootstrap method to call
    * @param  aReason
    *         The reason flag to pass to the bootstrap's startup method
    */
-  callBootstrapMethod: function XPI_callBootstrapMethod(aId, aVersion, aFile,
+  callBootstrapMethod: function XPI_callBootstrapMethod(aId, aVersion, aType, aFile,
                                                         aMethod, aReason) {
     // Never call any bootstrap methods in safe mode
     if (Services.appinfo.inSafeMode)
       return;
 
     // Load the scope if it hasn't already been loaded
     if (!(aId in this.bootstrapScopes))
-      this.loadBootstrapScope(aId, aFile, aVersion);
+      this.loadBootstrapScope(aId, aFile, aVersion, aType);
 
     if (!(aMethod in this.bootstrapScopes[aId])) {
       WARN("Add-on " + aId + " is missing bootstrap method " + aMethod);
       return;
     }
 
     let params = {
       id: aId,
@@ -3646,26 +3661,26 @@ var XPIProvider = {
       }
 
       if (!needsRestart) {
         aAddon.active = !isDisabled;
         XPIDatabase.updateAddonActive(aAddon);
         if (isDisabled) {
           if (aAddon.bootstrap) {
             let file = aAddon._installLocation.getLocationForID(aAddon.id);
-            this.callBootstrapMethod(aAddon.id, aAddon.version, file, "shutdown",
+            this.callBootstrapMethod(aAddon.id, aAddon.version, aAddon.type, file, "shutdown",
                                      BOOTSTRAP_REASONS.ADDON_DISABLE);
             this.unloadBootstrapScope(aAddon.id);
           }
           AddonManagerPrivate.callAddonListeners("onDisabled", wrapper);
         }
         else {
           if (aAddon.bootstrap) {
             let file = aAddon._installLocation.getLocationForID(aAddon.id);
-            this.callBootstrapMethod(aAddon.id, aAddon.version, file, "startup",
+            this.callBootstrapMethod(aAddon.id, aAddon.version, aAddon.type, file, "startup",
                                      BOOTSTRAP_REASONS.ADDON_ENABLE);
           }
           AddonManagerPrivate.callAddonListeners("onEnabled", wrapper);
         }
       }
     }
 
     // Notify any other providers that a new theme has been enabled
@@ -3723,21 +3738,21 @@ var XPIProvider = {
 
       if (!isAddonDisabled(aAddon) && !XPIProvider.enableRequiresRestart(aAddon)) {
         aAddon.active = true;
         XPIDatabase.updateAddonActive(aAddon);
       }
 
       if (aAddon.bootstrap) {
         let file = aAddon._installLocation.getLocationForID(aAddon.id);
-        XPIProvider.callBootstrapMethod(aAddon.id, aAddon.version, file,
+        XPIProvider.callBootstrapMethod(aAddon.id, aAddon.version, aAddon.type, file,
                                         "install", BOOTSTRAP_REASONS.ADDON_INSTALL);
 
         if (aAddon.active) {
-          XPIProvider.callBootstrapMethod(aAddon.id, aAddon.version, file,
+          XPIProvider.callBootstrapMethod(aAddon.id, aAddon.version, aAddon.type, file,
                                           "startup", BOOTSTRAP_REASONS.ADDON_INSTALL);
         }
         else {
           XPIProvider.unloadBootstrapScope(aAddon.id);
         }
       }
 
       // We always send onInstalled even if a restart is required to enable
@@ -3757,21 +3772,23 @@ var XPIProvider = {
           checkInstallLocation(aPos - 1);
       })
     }
 
     if (!requiresRestart) {
       if (aAddon.bootstrap) {
         let file = aAddon._installLocation.getLocationForID(aAddon.id);
         if (aAddon.active) {
-          this.callBootstrapMethod(aAddon.id, aAddon.version, file, "shutdown",
+          this.callBootstrapMethod(aAddon.id, aAddon.version, aAddon.type, file,
+                                   "shutdown",
                                    BOOTSTRAP_REASONS.ADDON_UNINSTALL);
         }
 
-        this.callBootstrapMethod(aAddon.id, aAddon.version, file, "uninstall",
+        this.callBootstrapMethod(aAddon.id, aAddon.version, aAddon.type, file,
+                                 "uninstall",
                                  BOOTSTRAP_REASONS.ADDON_UNINSTALL);
         this.unloadBootstrapScope(aAddon.id);
         flushStartupCache();
       }
       aAddon._installLocation.uninstallAddon(aAddon.id);
       XPIDatabase.removeAddonMetadata(aAddon);
       AddonManagerPrivate.callAddonListeners("onUninstalled", wrapper);
 
@@ -6348,22 +6365,24 @@ AddonInstall.prototype = {
             reason = BOOTSTRAP_REASONS.ADDON_DOWNGRADE;
 
           if (this.existingAddon.bootstrap) {
             let file = this.existingAddon._installLocation
                            .getLocationForID(this.existingAddon.id);
             if (this.existingAddon.active) {
               XPIProvider.callBootstrapMethod(this.existingAddon.id,
                                               this.existingAddon.version,
-                                              file, "shutdown", reason);
+                                              this.existingAddon.type, file,
+                                              "shutdown", reason);
             }
 
             XPIProvider.callBootstrapMethod(this.existingAddon.id,
                                             this.existingAddon.version,
-                                            file, "uninstall", reason);
+                                            this.existingAddon.type, file,
+                                            "uninstall", reason);
             XPIProvider.unloadBootstrapScope(this.existingAddon.id);
             flushStartupCache();
           }
 
           if (!isUpgrade && this.existingAddon.active) {
             this.existingAddon.active = false;
             XPIDatabase.updateAddonActive(this.existingAddon);
           }
@@ -6392,20 +6411,22 @@ AddonInstall.prototype = {
 
         // Retrieve the new DBAddonInternal for the add-on we just added
         let self = this;
         XPIDatabase.getAddonInLocation(this.addon.id, this.installLocation.name,
                                        function(a) {
           self.addon = a;
           if (self.addon.bootstrap) {
             XPIProvider.callBootstrapMethod(self.addon.id, self.addon.version,
-                                            file, "install", reason);
+                                            self.addon.type, file, "install",
+                                            reason);
             if (self.addon.active) {
               XPIProvider.callBootstrapMethod(self.addon.id, self.addon.version,
-                                              file, "startup", reason);
+                                              self.addon.type, file, "startup",
+                                              reason);
             }
             else {
               XPIProvider.unloadBootstrapScope(self.addon.id);
             }
           }
           AddonManagerPrivate.callAddonListeners("onInstalled",
                                                  createWrapper(self.addon));
 
@@ -7961,13 +7982,17 @@ WinRegInstallLocation.prototype = {
 
 AddonManagerPrivate.registerProvider(XPIProvider, [
   new AddonManagerPrivate.AddonType("extension", URI_EXTENSION_STRINGS,
                                     STRING_TYPE_NAME,
                                     AddonManager.VIEW_TYPE_LIST, 4000),
   new AddonManagerPrivate.AddonType("theme", URI_EXTENSION_STRINGS,
                                     STRING_TYPE_NAME,
                                     AddonManager.VIEW_TYPE_LIST, 5000),
+  new AddonManagerPrivate.AddonType("dictionary", URI_EXTENSION_STRINGS,
+                                    STRING_TYPE_NAME,
+                                    AddonManager.VIEW_TYPE_LIST, 7000,
+                                    AddonManager.TYPE_UI_HIDE_EMPTY),
   new AddonManagerPrivate.AddonType("locale", URI_EXTENSION_STRINGS,
                                     STRING_TYPE_NAME,
-                                    AddonManager.VIEW_TYPE_LIST, 2000,
+                                    AddonManager.VIEW_TYPE_LIST, 8000,
                                     AddonManager.TYPE_UI_HIDE_EMPTY)
 ]);
--- a/toolkit/mozapps/extensions/nsBlocklistService.js
+++ b/toolkit/mozapps/extensions/nsBlocklistService.js
@@ -902,17 +902,17 @@ Blocklist.prototype = {
       }
     }
   },
 
   _blocklistUpdated: function(oldAddonEntries, oldPluginEntries) {
     var addonList = [];
 
     var self = this;
-    AddonManager.getAddonsByTypes(["extension", "theme", "locale"], function(addons) {
+    AddonManager.getAddonsByTypes(["extension", "theme", "locale", "dictionary"], function(addons) {
 
       for (let i = 0; i < addons.length; i++) {
         let oldState = Ci.nsIBlocklistService.STATE_NOTBLOCKED;
         if (oldAddonEntries)
           oldState = self._getAddonBlocklistState(addons[i].id, addons[i].version,
                                                   oldAddonEntries);
         let state = self.getAddonBlocklistState(addons[i].id, addons[i].version);
 
new file mode 100644
--- /dev/null
+++ b/toolkit/mozapps/extensions/test/addons/test_dictionary/dictionaries/ab-CD.dic
@@ -0,0 +1,2 @@
+1
+test1
new file mode 100644
--- /dev/null
+++ b/toolkit/mozapps/extensions/test/addons/test_dictionary/install.rdf
@@ -0,0 +1,25 @@
+<?xml version="1.0"?>
+
+<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+     xmlns:em="http://www.mozilla.org/2004/em-rdf#">
+
+  <Description about="urn:mozilla:install-manifest">
+    <em:id>ab-CD@dictionaries.addons.mozilla.org</em:id>
+    <em:version>1.0</em:version>
+    <em:type>64</em:type>
+    <em:unpack>true</em:unpack>
+
+    <!-- Front End MetaData -->
+    <em:name>Test Dictionary</em:name>
+    <em:description>Test Description</em:description>
+
+    <em:targetApplication>
+      <Description>
+        <em:id>xpcshell@tests.mozilla.org</em:id>
+        <em:minVersion>1</em:minVersion>
+        <em:maxVersion>1</em:maxVersion>
+      </Description>
+    </em:targetApplication>
+
+  </Description>
+</RDF>
new file mode 100644
--- /dev/null
+++ b/toolkit/mozapps/extensions/test/addons/test_dictionary_2/dictionaries/ab-CD.dic
@@ -0,0 +1,2 @@
+1
+test2
new file mode 100644
--- /dev/null
+++ b/toolkit/mozapps/extensions/test/addons/test_dictionary_2/install.rdf
@@ -0,0 +1,24 @@
+<?xml version="1.0"?>
+
+<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+     xmlns:em="http://www.mozilla.org/2004/em-rdf#">
+
+  <Description about="urn:mozilla:install-manifest">
+    <em:id>ab-CD@dictionaries.addons.mozilla.org</em:id>
+    <em:version>2.0</em:version>
+    <em:unpack>true</em:unpack>
+
+    <!-- Front End MetaData -->
+    <em:name>Test Dictionary</em:name>
+    <em:description>Test Description</em:description>
+
+    <em:targetApplication>
+      <Description>
+        <em:id>xpcshell@tests.mozilla.org</em:id>
+        <em:minVersion>1</em:minVersion>
+        <em:maxVersion>1</em:maxVersion>
+      </Description>
+    </em:targetApplication>
+
+  </Description>
+</RDF>
new file mode 100644
--- /dev/null
+++ b/toolkit/mozapps/extensions/test/xpcshell/test_dictionary.js
@@ -0,0 +1,628 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+// This verifies that bootstrappable add-ons can be used without restarts.
+Components.utils.import("resource://gre/modules/Services.jsm");
+
+// Enable loading extensions from the user scopes
+Services.prefs.setIntPref("extensions.enabledScopes",
+                          AddonManager.SCOPE_PROFILE + AddonManager.SCOPE_USER);
+
+createAppInfo("xpcshell@tests.mozilla.org", "XPCShell", "1", "1.9.2");
+
+const profileDir = gProfD.clone();
+profileDir.append("extensions");
+const userExtDir = gProfD.clone();
+userExtDir.append("extensions2");
+userExtDir.append(gAppInfo.ID);
+registerDirectory("XREUSysExt", userExtDir.parent);
+
+do_load_httpd_js();
+var testserver;
+
+/**
+ * This object is both a factory and an mozISpellCheckingEngine implementation (so, it
+ * is de-facto a service). It's also an interface requestor that gives out
+ * itself when asked for mozISpellCheckingEngine.
+ */
+var HunspellEngine = {
+  dictionaryDirs: [],
+  
+  QueryInterface: function hunspell_qi(iid) {
+    if (iid.equals(Components.interfaces.nsISupports) ||
+        iid.equals(Components.interfaces.nsIFactory) ||
+        iid.equals(Components.interfaces.mozISpellCheckingEngine))
+      return this;
+    throw Components.results.NS_ERROR_NO_INTERFACE;
+  },
+  createInstance: function hunspell_ci(outer, iid) {
+    if (outer)
+      throw Components.results.NS_ERROR_NO_AGGREGATION;
+    return this.QueryInterface(iid);
+  },
+  lockFactory: function hunspell_lockf(lock) {
+    throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
+  },
+
+  addDirectory: function hunspell_addDirectory(dir) {
+    this.dictionaryDirs.push(dir);
+  },
+
+  removeDirectory: function hunspell_addDirectory(dir) {
+    this.dictionaryDirs.splice(this.dictionaryDirs.indexOf(dir), 1);
+  },
+
+  getInterface: function hunspell_gi(iid) {
+    if (iid.equals(Components.interfaces.mozISpellCheckingEngine))
+      return this;
+    throw Components.results.NS_ERROR_NO_INTERFACE;
+  },
+
+  contractID: "@mozilla.org/spellchecker/engine;1",
+  classID: Components.ID("{6f3c63bc-a4fd-449b-9a58-a2d9bd972cce}"),
+
+  activate: function hunspell_activate() {
+    this.origClassID = Components.manager.nsIComponentRegistrar
+      .contractIDToCID(this.contractID);
+    this.origFactory = Components.manager
+      .getClassObject(Components.classes[this.contractID],
+                      Components.interfaces.nsIFactory);
+
+    Components.manager.nsIComponentRegistrar
+      .unregisterFactory(this.origClassID, this.origFactory);
+    Components.manager.nsIComponentRegistrar.registerFactory(this.classID,
+      "Test hunspell", this.contractID, this);
+  },
+  
+  deactivate: function hunspell_deactivate() {
+    Components.manager.nsIComponentRegistrar.unregisterFactory(this.classID, this);
+    Components.manager.nsIComponentRegistrar.registerFactory(this.origClassID,
+      "Hunspell", this.contractID, this.origFactory);
+  },
+
+  isDictionaryEnabled: function hunspell_isDictionaryEnabled(name) {
+    return this.dictionaryDirs.some(function(dir) {
+      var dic = dir.clone();
+      dic.append(name);
+      return dic.exists();
+    });
+  }
+};
+
+function run_test() {
+  do_test_pending();
+
+  // Create and configure the HTTP server.
+  testserver = new nsHttpServer();
+  testserver.registerDirectory("/addons/", do_get_file("addons"));
+  testserver.start(4444);
+
+  startupManager();
+
+  run_test_1();
+}
+
+// Tests that installing doesn't require a restart
+function run_test_1() {
+  prepare_test({ }, [
+    "onNewInstall"
+  ]);
+
+  HunspellEngine.activate();
+
+  AddonManager.getInstallForFile(do_get_addon("test_dictionary"), function(install) {
+    ensure_test_completed();
+
+    do_check_neq(install, null);
+    do_check_eq(install.type, "dictionary");
+    do_check_eq(install.version, "1.0");
+    do_check_eq(install.name, "Test Dictionary");
+    do_check_eq(install.state, AddonManager.STATE_DOWNLOADED);
+    do_check_true(install.addon.hasResource("install.rdf"));
+    do_check_false(install.addon.hasResource("bootstrap.js"));
+    do_check_eq(install.addon.operationsRequiringRestart &
+                AddonManager.OP_NEEDS_RESTART_INSTALL, 0);
+    do_check_not_in_crash_annotation("ab-CD@dictionaries.addons.mozilla.org", "1.0");
+
+    let addon = install.addon;
+    prepare_test({
+      "ab-CD@dictionaries.addons.mozilla.org": [
+        ["onInstalling", false],
+        "onInstalled"
+      ]
+    }, [
+      "onInstallStarted",
+      "onInstallEnded",
+    ], function() {
+      do_check_true(addon.hasResource("install.rdf"));
+      check_test_1();
+    });
+    install.install();
+  });
+}
+
+function check_test_1() {
+  AddonManager.getAllInstalls(function(installs) {
+    // There should be no active installs now since the install completed and
+    // doesn't require a restart.
+    do_check_eq(installs.length, 0);
+
+    AddonManager.getAddonByID("ab-CD@dictionaries.addons.mozilla.org", function(b1) {
+      do_check_neq(b1, null);
+      do_check_eq(b1.version, "1.0");
+      do_check_false(b1.appDisabled);
+      do_check_false(b1.userDisabled);
+      do_check_true(b1.isActive);
+      do_check_true(HunspellEngine.isDictionaryEnabled("ab-CD.dic"));
+      do_check_true(b1.hasResource("install.rdf"));
+      do_check_false(b1.hasResource("bootstrap.js"));
+      do_check_in_crash_annotation("ab-CD@dictionaries.addons.mozilla.org", "1.0");
+
+      let dir = do_get_addon_root_uri(profileDir, "ab-CD@dictionaries.addons.mozilla.org");
+
+      AddonManager.getAddonsWithOperationsByTypes(null, function(list) {
+        do_check_eq(list.length, 0);
+
+        run_test_2();
+      });
+    });
+  });
+}
+
+// Tests that disabling doesn't require a restart
+function run_test_2() {
+  AddonManager.getAddonByID("ab-CD@dictionaries.addons.mozilla.org", function(b1) {
+    prepare_test({
+      "ab-CD@dictionaries.addons.mozilla.org": [
+        ["onDisabling", false],
+        "onDisabled"
+      ]
+    });
+
+    do_check_eq(b1.operationsRequiringRestart &
+                AddonManager.OP_NEEDS_RESTART_DISABLE, 0);
+    b1.userDisabled = true;
+    ensure_test_completed();
+
+    do_check_neq(b1, null);
+    do_check_eq(b1.version, "1.0");
+    do_check_false(b1.appDisabled);
+    do_check_true(b1.userDisabled);
+    do_check_false(b1.isActive);
+    do_check_false(HunspellEngine.isDictionaryEnabled("ab-CD.dic"));
+    do_check_not_in_crash_annotation("ab-CD@dictionaries.addons.mozilla.org", "1.0");
+
+    AddonManager.getAddonByID("ab-CD@dictionaries.addons.mozilla.org", function(newb1) {
+      do_check_neq(newb1, null);
+      do_check_eq(newb1.version, "1.0");
+      do_check_false(newb1.appDisabled);
+      do_check_true(newb1.userDisabled);
+      do_check_false(newb1.isActive);
+
+      run_test_3();
+    });
+  });
+}
+
+// Test that restarting doesn't accidentally re-enable
+function run_test_3() {
+  shutdownManager();
+  do_check_false(HunspellEngine.isDictionaryEnabled("ab-CD.dic"));
+  startupManager(false);
+  do_check_false(HunspellEngine.isDictionaryEnabled("ab-CD.dic"));
+  do_check_not_in_crash_annotation("ab-CD@dictionaries.addons.mozilla.org", "1.0");
+
+  AddonManager.getAddonByID("ab-CD@dictionaries.addons.mozilla.org", function(b1) {
+    do_check_neq(b1, null);
+    do_check_eq(b1.version, "1.0");
+    do_check_false(b1.appDisabled);
+    do_check_true(b1.userDisabled);
+    do_check_false(b1.isActive);
+
+    run_test_4();
+  });
+}
+
+// Tests that enabling doesn't require a restart
+function run_test_4() {
+  AddonManager.getAddonByID("ab-CD@dictionaries.addons.mozilla.org", function(b1) {
+    prepare_test({
+      "ab-CD@dictionaries.addons.mozilla.org": [
+        ["onEnabling", false],
+        "onEnabled"
+      ]
+    });
+
+    do_check_eq(b1.operationsRequiringRestart &
+                AddonManager.OP_NEEDS_RESTART_ENABLE, 0);
+    b1.userDisabled = false;
+    ensure_test_completed();
+
+    do_check_neq(b1, null);
+    do_check_eq(b1.version, "1.0");
+    do_check_false(b1.appDisabled);
+    do_check_false(b1.userDisabled);
+    do_check_true(b1.isActive);
+    do_check_true(HunspellEngine.isDictionaryEnabled("ab-CD.dic"));
+    do_check_in_crash_annotation("ab-CD@dictionaries.addons.mozilla.org", "1.0");
+
+    AddonManager.getAddonByID("ab-CD@dictionaries.addons.mozilla.org", function(newb1) {
+      do_check_neq(newb1, null);
+      do_check_eq(newb1.version, "1.0");
+      do_check_false(newb1.appDisabled);
+      do_check_false(newb1.userDisabled);
+      do_check_true(newb1.isActive);
+
+      run_test_5();
+    });
+  });
+}
+
+// Tests that a restart shuts down and restarts the add-on
+function run_test_5() {
+  shutdownManager();
+  do_check_false(HunspellEngine.isDictionaryEnabled("ab-CD.dic"));
+  do_check_not_in_crash_annotation("ab-CD@dictionaries.addons.mozilla.org", "1.0");
+  startupManager(false);
+  do_check_true(HunspellEngine.isDictionaryEnabled("ab-CD.dic"));
+  do_check_in_crash_annotation("ab-CD@dictionaries.addons.mozilla.org", "1.0");
+
+  AddonManager.getAddonByID("ab-CD@dictionaries.addons.mozilla.org", function(b1) {
+    do_check_neq(b1, null);
+    do_check_eq(b1.version, "1.0");
+    do_check_false(b1.appDisabled);
+    do_check_false(b1.userDisabled);
+    do_check_true(b1.isActive);
+    do_check_false(isExtensionInAddonsList(profileDir, b1.id));
+
+    run_test_7();
+  });
+}
+
+// Tests that uninstalling doesn't require a restart
+function run_test_7() {
+  AddonManager.getAddonByID("ab-CD@dictionaries.addons.mozilla.org", function(b1) {
+    prepare_test({
+      "ab-CD@dictionaries.addons.mozilla.org": [
+        ["onUninstalling", false],
+        "onUninstalled"
+      ]
+    });
+
+    do_check_eq(b1.operationsRequiringRestart &
+                AddonManager.OP_NEEDS_RESTART_UNINSTALL, 0);
+    b1.uninstall();
+
+    check_test_7();
+  });
+}
+
+function check_test_7() {
+  ensure_test_completed();
+  do_check_false(HunspellEngine.isDictionaryEnabled("ab-CD.dic"));
+  do_check_not_in_crash_annotation("ab-CD@dictionaries.addons.mozilla.org", "1.0");
+
+  AddonManager.getAddonByID("ab-CD@dictionaries.addons.mozilla.org", function(b1) {
+    do_check_eq(b1, null);
+
+    restartManager();
+
+    AddonManager.getAddonByID("ab-CD@dictionaries.addons.mozilla.org", function(newb1) {
+      do_check_eq(newb1, null);
+
+      run_test_8();
+    });
+  });
+}
+
+// Test that a bootstrapped extension dropped into the profile loads properly
+// on startup and doesn't cause an EM restart
+function run_test_8() {
+  shutdownManager();
+
+  let dir = profileDir.clone();
+  dir.append("ab-CD@dictionaries.addons.mozilla.org");
+  dir.create(AM_Ci.nsIFile.DIRECTORY_TYPE, 0755);
+  let zip = AM_Cc["@mozilla.org/libjar/zip-reader;1"].
+            createInstance(AM_Ci.nsIZipReader);
+  zip.open(do_get_addon("test_dictionary"));
+  dir.append("install.rdf");
+  zip.extract("install.rdf", dir);
+  dir = dir.parent;
+  dir.append("dictionaries");
+  dir.create(AM_Ci.nsIFile.DIRECTORY_TYPE, 0755);
+  dir.append("ab-CD.dic");
+  zip.extract("dictionaries/ab-CD.dic", dir);
+  zip.close();
+
+  startupManager(false);
+
+  AddonManager.getAddonByID("ab-CD@dictionaries.addons.mozilla.org", function(b1) {
+    do_check_neq(b1, null);
+    do_check_eq(b1.version, "1.0");
+    do_check_false(b1.appDisabled);
+    do_check_false(b1.userDisabled);
+    do_check_true(b1.isActive);
+    do_check_true(HunspellEngine.isDictionaryEnabled("ab-CD.dic"));
+    do_check_in_crash_annotation("ab-CD@dictionaries.addons.mozilla.org", "1.0");
+
+    run_test_9();
+  });
+}
+
+// Test that items detected as removed during startup get removed properly
+function run_test_9() {
+  shutdownManager();
+
+  let dir = profileDir.clone();
+  dir.append("ab-CD@dictionaries.addons.mozilla.org");
+  dir.remove(true);
+  startupManager(false);
+
+  AddonManager.getAddonByID("ab-CD@dictionaries.addons.mozilla.org", function(b1) {
+    do_check_eq(b1, null);
+    do_check_not_in_crash_annotation("ab-CD@dictionaries.addons.mozilla.org", "1.0");
+
+    run_test_12();
+  });
+}
+
+
+// Tests that bootstrapped extensions are correctly loaded even if the app is
+// upgraded at the same time
+function run_test_12() {
+  shutdownManager();
+
+  let dir = profileDir.clone();
+  dir.append("ab-CD@dictionaries.addons.mozilla.org");
+  dir.create(AM_Ci.nsIFile.DIRECTORY_TYPE, 0755);
+  let zip = AM_Cc["@mozilla.org/libjar/zip-reader;1"].
+            createInstance(AM_Ci.nsIZipReader);
+  zip.open(do_get_addon("test_dictionary"));
+  dir.append("install.rdf");
+  zip.extract("install.rdf", dir);
+  dir = dir.parent;
+  dir.append("dictionaries");
+  dir.create(AM_Ci.nsIFile.DIRECTORY_TYPE, 0755);
+  dir.append("ab-CD.dic");
+  zip.extract("dictionaries/ab-CD.dic", dir);
+  zip.close();
+
+  startupManager(true);
+
+  AddonManager.getAddonByID("ab-CD@dictionaries.addons.mozilla.org", function(b1) {
+    do_check_neq(b1, null);
+    do_check_eq(b1.version, "1.0");
+    do_check_false(b1.appDisabled);
+    do_check_false(b1.userDisabled);
+    do_check_true(b1.isActive);
+    do_check_true(HunspellEngine.isDictionaryEnabled("ab-CD.dic"));
+    do_check_in_crash_annotation("ab-CD@dictionaries.addons.mozilla.org", "1.0");
+
+    b1.uninstall();
+    restartManager();
+
+    run_test_16();
+  });
+}
+
+
+// Tests that bootstrapped extensions don't get loaded when in safe mode
+function run_test_16() {
+  installAllFiles([do_get_addon("test_dictionary")], function() {
+    AddonManager.getAddonByID("ab-CD@dictionaries.addons.mozilla.org", function(b1) {
+      // Should have installed and started
+      do_check_true(HunspellEngine.isDictionaryEnabled("ab-CD.dic"));
+
+      shutdownManager();
+
+      // Should have stopped
+      do_check_false(HunspellEngine.isDictionaryEnabled("ab-CD.dic"));
+
+      gAppInfo.inSafeMode = true;
+      startupManager(false);
+
+      AddonManager.getAddonByID("ab-CD@dictionaries.addons.mozilla.org", function(b1) {
+        // Should still be stopped
+        do_check_false(HunspellEngine.isDictionaryEnabled("ab-CD.dic"));
+        do_check_false(b1.isActive);
+
+        shutdownManager();
+        gAppInfo.inSafeMode = false;
+        startupManager(false);
+
+        // Should have started
+        do_check_true(HunspellEngine.isDictionaryEnabled("ab-CD.dic"));
+
+        AddonManager.getAddonByID("ab-CD@dictionaries.addons.mozilla.org", function(b1) {
+          b1.uninstall();
+
+          run_test_17();
+        });
+      });
+    });
+  });
+}
+
+// Check that a bootstrapped extension in a non-profile location is loaded
+function run_test_17() {
+  shutdownManager();
+
+  let dir = userExtDir.clone();
+  dir.append("ab-CD@dictionaries.addons.mozilla.org");
+  dir.create(AM_Ci.nsIFile.DIRECTORY_TYPE, 0755);
+  let zip = AM_Cc["@mozilla.org/libjar/zip-reader;1"].
+            createInstance(AM_Ci.nsIZipReader);
+  zip.open(do_get_addon("test_dictionary"));
+  dir.append("install.rdf");
+  zip.extract("install.rdf", dir);
+  dir = dir.parent;
+  dir.append("dictionaries");
+  dir.create(AM_Ci.nsIFile.DIRECTORY_TYPE, 0755);
+  dir.append("ab-CD.dic");
+  zip.extract("dictionaries/ab-CD.dic", dir);
+  zip.close();
+
+  startupManager();
+
+  AddonManager.getAddonByID("ab-CD@dictionaries.addons.mozilla.org", function(b1) {
+    // Should have installed and started
+    do_check_true(HunspellEngine.isDictionaryEnabled("ab-CD.dic"));
+    do_check_neq(b1, null);
+    do_check_eq(b1.version, "1.0");
+    do_check_true(b1.isActive);
+
+    // From run_test_21
+    dir = userExtDir.clone();
+    dir.append("ab-CD@dictionaries.addons.mozilla.org");
+    dir.remove(true);
+
+    restartManager();
+
+    run_test_23();
+  });
+}
+
+// Tests that installing from a URL doesn't require a restart
+function run_test_23() {
+  prepare_test({ }, [
+    "onNewInstall"
+  ]);
+
+  let url = "http://localhost:4444/addons/test_dictionary.xpi";
+  AddonManager.getInstallForURL(url, function(install) {
+    ensure_test_completed();
+
+    do_check_neq(install, null);
+
+    prepare_test({ }, [
+      "onDownloadStarted",
+      "onDownloadEnded"
+    ], function() {
+      do_check_eq(install.type, "dictionary");
+      do_check_eq(install.version, "1.0");
+      do_check_eq(install.name, "Test Dictionary");
+      do_check_eq(install.state, AddonManager.STATE_DOWNLOADED);
+      do_check_true(install.addon.hasResource("install.rdf"));
+      do_check_false(install.addon.hasResource("bootstrap.js"));
+      do_check_eq(install.addon.operationsRequiringRestart &
+                  AddonManager.OP_NEEDS_RESTART_INSTALL, 0);
+      do_check_not_in_crash_annotation("ab-CD@dictionaries.addons.mozilla.org", "1.0");
+
+      let addon = install.addon;
+      prepare_test({
+        "ab-CD@dictionaries.addons.mozilla.org": [
+          ["onInstalling", false],
+          "onInstalled"
+        ]
+      }, [
+        "onInstallStarted",
+        "onInstallEnded",
+      ], function() {
+        do_check_true(addon.hasResource("install.rdf"));
+        check_test_23();
+      });
+    });
+    install.install();
+  }, "application/x-xpinstall");
+}
+
+function check_test_23() {
+  AddonManager.getAllInstalls(function(installs) {
+    // There should be no active installs now since the install completed and
+    // doesn't require a restart.
+    do_check_eq(installs.length, 0);
+
+    AddonManager.getAddonByID("ab-CD@dictionaries.addons.mozilla.org", function(b1) {
+      do_check_neq(b1, null);
+      do_check_eq(b1.version, "1.0");
+      do_check_false(b1.appDisabled);
+      do_check_false(b1.userDisabled);
+      do_check_true(b1.isActive);
+      do_check_true(HunspellEngine.isDictionaryEnabled("ab-CD.dic"));
+      do_check_true(b1.hasResource("install.rdf"));
+      do_check_false(b1.hasResource("bootstrap.js"));
+      do_check_in_crash_annotation("ab-CD@dictionaries.addons.mozilla.org", "1.0");
+
+      let dir = do_get_addon_root_uri(profileDir, "ab-CD@dictionaries.addons.mozilla.org");
+
+      AddonManager.getAddonsWithOperationsByTypes(null, function(list) {
+        do_check_eq(list.length, 0);
+
+        restartManager();
+        AddonManager.getAddonByID("ab-CD@dictionaries.addons.mozilla.org", function(b1) {
+          b1.uninstall();
+          restartManager();
+
+          testserver.stop(run_test_25);
+        });
+      });
+    });
+  });
+}
+
+// Tests that updating from a bootstrappable add-on to a normal add-on calls
+// the uninstall method
+function run_test_25() {
+  installAllFiles([do_get_addon("test_dictionary")], function() {
+    do_check_true(HunspellEngine.isDictionaryEnabled("ab-CD.dic"));
+
+    installAllFiles([do_get_addon("test_dictionary_2")], function() {
+      // Needs a restart to complete this so the old version stays running
+      do_check_true(HunspellEngine.isDictionaryEnabled("ab-CD.dic"));
+
+      AddonManager.getAddonByID("ab-CD@dictionaries.addons.mozilla.org", function(b1) {
+        do_check_neq(b1, null);
+        do_check_eq(b1.version, "1.0");
+        do_check_true(b1.isActive);
+        do_check_true(hasFlag(b1.pendingOperations, AddonManager.PENDING_UPGRADE));
+
+        restartManager();
+
+        do_check_false(HunspellEngine.isDictionaryEnabled("ab-CD.dic"));
+
+        AddonManager.getAddonByID("ab-CD@dictionaries.addons.mozilla.org", function(b1) {
+          do_check_neq(b1, null);
+          do_check_eq(b1.version, "2.0");
+          do_check_true(b1.isActive);
+          do_check_eq(b1.pendingOperations, AddonManager.PENDING_NONE);
+
+          run_test_26();
+        });
+      });
+    });
+  });
+}
+
+// Tests that updating from a normal add-on to a bootstrappable add-on calls
+// the install method
+function run_test_26() {
+  installAllFiles([do_get_addon("test_dictionary")], function() {
+    // Needs a restart to complete this
+    do_check_false(HunspellEngine.isDictionaryEnabled("ab-CD.dic"));
+
+    AddonManager.getAddonByID("ab-CD@dictionaries.addons.mozilla.org", function(b1) {
+      do_check_neq(b1, null);
+      do_check_eq(b1.version, "2.0");
+      do_check_true(b1.isActive);
+      do_check_true(hasFlag(b1.pendingOperations, AddonManager.PENDING_UPGRADE));
+
+      restartManager();
+
+      do_check_true(HunspellEngine.isDictionaryEnabled("ab-CD.dic"));
+
+      AddonManager.getAddonByID("ab-CD@dictionaries.addons.mozilla.org", function(b1) {
+        do_check_neq(b1, null);
+        do_check_eq(b1.version, "1.0");
+        do_check_true(b1.isActive);
+        do_check_eq(b1.pendingOperations, AddonManager.PENDING_NONE);
+
+        HunspellEngine.deactivate();
+
+        do_test_finished();
+      });
+    });
+  });
+}
+
--- a/toolkit/mozapps/extensions/test/xpcshell/xpcshell.ini
+++ b/toolkit/mozapps/extensions/test/xpcshell/xpcshell.ini
@@ -115,16 +115,17 @@ fail-if = os == "android"
 fail-if = os == "android"
 [test_bug619730.js]
 [test_bug620837.js]
 [test_bug655254.js]
 [test_bug659772.js]
 [test_cacheflush.js]
 [test_checkcompatibility.js]
 [test_corrupt.js]
+[test_dictionary.js]
 [test_disable.js]
 [test_distribution.js]
 [test_dss.js]
 # Bug 676992: test consistently fails on Android
 fail-if = os == "android"
 [test_duplicateplugins.js]
 # Bug 676992: test consistently hangs on Android
 skip-if = os == "android"
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..a1e0d53596d2bd0fe1a89a160f1e6dba5ff83af8
GIT binary patch
literal 1290
zc$@(W1@-!gP)<h;3K|Lk000e1NJLTq001BW001Be1^@s6b9#F80000PbVXQnQ*UN;
zcVTj606}DLVr3vnZDD6+Qe|Oed2z{QJOBU$tVu*cR9M61mdlGARTRd5=iGa%AJa27
zCI&SQlbA$E5E2YNqKP9hf}$7~gCPC^x`<f?(Upj6@egogKu`o<U{-_RDk6wRWFk>f
z6JjQrJZ2Kp>FGz^>!PZ<yCz+sCz6#7MOWYITjx99_nmVt{NF!P^x(C9Y!>*k-DO*3
zq3hx49RoW;dLIhj(qBIg?0^1UejgUc76DM@{qY?Kw(gpKhHABX(;1#Pabnxz;^NEj
z=G!APaNtSy-oEkSuXn%r4m)@5{7)1&n@whCXBWoD$Jfuy%ydTu@D=cECx*y?_wdw?
zl-6Op!VTWq-*e=J_jqn32|{4{{;lhoztCXIhC5lje3gycHh~C)ke4`HlL9-1!1A>v
z=KuU@dSnj-s7=(yIkT|D@|9DxuC`dd6z2_Clx@zK0b5x|d29^<Y9j-X0IJ}-O<Gqy
z?Iv_v^M#HVQexz~3P9B1#@6BeaDs{$00JR+L=tw5YPLF5dr=T1_goNE4JwKcs{r6r
zNks(JfC^wrx#TmZSF$22{a_r3QV_qG0ZIL(Nl!qv)RQL(5D@yN%%K`Eriww;5LP8Y
z0IQ$`jL85*{U|vz<}<#w9OGlCRtzcuH4ZTbU)1ml84wUrR8mvgD7_r24mDAKO&y|+
zR@<_6(>^xueS>COK})D{sOst&P!&|bXmY7ZB=BBnv^p3SDrM7Sz1{ZIC$}>-eF$Sq
z#O(&>e*6G67EwzaR>^=$012q3RbWa4aWq?S@9u-F*|3LpM-h$a#E!8wTbO#{^;GX}
z;(imM5+PDJa*7!cLRx;HCaLG(V<sPbiTcJp)TbW7$1SeR&r!YYE~XwogsLU@4wp}T
z$HLDa<Dya`kuim3s71((5sXSAfskq$VNi%W5QNExUZK8zJClzc#6~snT^fHM<Lvi`
ziJ~$tDj}%^e$^gG#mFR38{rI`|Mdu38E4||2M}wyXV<Igo-WIaCpmNMLtM#XO|nsp
zLydv3S_w3%bEBygwuFX&8qfK;Pf=T@y7oRqgb)Iq#sc#{9L6d*TTTjABq>9=2@_fY
z6~Rc-6U4ZL1zRF=5f|n@qqX!GgqXN_iF3z3!r&>D%f0eUvUjMt853$+1t#e|s;<}R
zA`9J)=fd$XSi5yU7k`^YeG6BvTsN%LM2MQzc>qWZDAMl(HX1AuB86@oxcJNGs4BKn
z9%$3_T6EF}Os->(#z0sx3o;r9hK)0U2$w&U^qwaZMU2H5H}WtNKs;bf)__1|5WtO&
zW%;=fLO{eIB3U2M^q-*!fC5p{1d|LjUDT|bNkMRBC_pt9m7WA8pbf;s00`iKF;6lJ
zk}^sMV8%dNc73)bFU{aLNgu%4Y#5ED5Pb&KuE@R&Ok}Cps76$CM9l`aTptK9Ffz0A
zQ|RH#-HWXOLP&5<09~Myu`mokH3T@b@DKPHSGogJa+pfJcTx#yge?2s@AOC}IUm5n
z=|3_Csz4KH3<F?*2+&rSqn~_p_E81Cox6evoId$hFL?%t$e)B(9MM9bs78yUna9#t
zot0jWfO^Wpt^6zlOQ{)i05nCWw-|s=>GuHt0$Pu(QF_|%DF6Tf07*qoM6N<$f<-z$
A=l}o!
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..08a0447a4703e943d433efe97e98ecd4a2bd9f23
GIT binary patch
literal 584
zc$@)90=NB%P)<h;3K|Lk000e1NJLTq000mG000mO1^@s6AM^iV0000PbVXQnQ*UN;
zcVTj606}DLVr3vnZDD6+Qe|Oed2z{QJOBUz>PbXFR5*=&kk3n0Q5?lT-*@kQ@80Jd
zV~j{aMllIYk<h@En+U2!NYJJ~pjEZ#AE;%!*6rFy1pR<kLHk+=X%sP079qUE%E1}O
zdH1$(CLQW|;4bbL&f#;8gb)C@c}`9NFMwKgKr?^BQld5B;?ljXcL2I~4T0O~#D$@m
z#jDh6wK6mHdcBtC`L!ju1t2|w>t|&fa2*flPY;v^bk%(DawqL40JktV&CjhS6VsEW
z&d%-*pWnZ6z5m|;A3*Df#>N*K-y0=%p)xv$?^5>@1W*wu0cH9J>=c1k+oK{76;t^A
zfaoBB5>QG|#?mSbt-^pxP)UW^%Xc|Ceg-7Md;T9_l%SP>a*WPiVr>2jZJ#i{c!R-_
z8LDFoNM!m5`YLE8XceK2WpHGgY<P;w@hQ?{ll=brntb&cmEn`+6^z<@vCCLre#rKZ
zkJ#!c&5cj2FFzu2DRGh>vVj7nB3znbttDT1!gl_FeDx`bwYW4xn*?80!9=pRL!6>x
z=oFq`^;g73p;ZQe(#gLBA|eL~bZpVF#k!P%EW^6Advhog;{!Zj>BvEXBm^jmg7nBR
z$<PF4>a=%y6%wG;3vk}EdH?a-st9~ryHgs_-D?wYKubahh=>7VAROx4mjLY$!tNib
W@~wW0lI!mP0000<MNUMnLSTaHAql+z
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..a1e0d53596d2bd0fe1a89a160f1e6dba5ff83af8
GIT binary patch
literal 1290
zc$@(W1@-!gP)<h;3K|Lk000e1NJLTq001BW001Be1^@s6b9#F80000PbVXQnQ*UN;
zcVTj606}DLVr3vnZDD6+Qe|Oed2z{QJOBU$tVu*cR9M61mdlGARTRd5=iGa%AJa27
zCI&SQlbA$E5E2YNqKP9hf}$7~gCPC^x`<f?(Upj6@egogKu`o<U{-_RDk6wRWFk>f
z6JjQrJZ2Kp>FGz^>!PZ<yCz+sCz6#7MOWYITjx99_nmVt{NF!P^x(C9Y!>*k-DO*3
zq3hx49RoW;dLIhj(qBIg?0^1UejgUc76DM@{qY?Kw(gpKhHABX(;1#Pabnxz;^NEj
z=G!APaNtSy-oEkSuXn%r4m)@5{7)1&n@whCXBWoD$Jfuy%ydTu@D=cECx*y?_wdw?
zl-6Op!VTWq-*e=J_jqn32|{4{{;lhoztCXIhC5lje3gycHh~C)ke4`HlL9-1!1A>v
z=KuU@dSnj-s7=(yIkT|D@|9DxuC`dd6z2_Clx@zK0b5x|d29^<Y9j-X0IJ}-O<Gqy
z?Iv_v^M#HVQexz~3P9B1#@6BeaDs{$00JR+L=tw5YPLF5dr=T1_goNE4JwKcs{r6r
zNks(JfC^wrx#TmZSF$22{a_r3QV_qG0ZIL(Nl!qv)RQL(5D@yN%%K`Eriww;5LP8Y
z0IQ$`jL85*{U|vz<}<#w9OGlCRtzcuH4ZTbU)1ml84wUrR8mvgD7_r24mDAKO&y|+
zR@<_6(>^xueS>COK})D{sOst&P!&|bXmY7ZB=BBnv^p3SDrM7Sz1{ZIC$}>-eF$Sq
z#O(&>e*6G67EwzaR>^=$012q3RbWa4aWq?S@9u-F*|3LpM-h$a#E!8wTbO#{^;GX}
z;(imM5+PDJa*7!cLRx;HCaLG(V<sPbiTcJp)TbW7$1SeR&r!YYE~XwogsLU@4wp}T
z$HLDa<Dya`kuim3s71((5sXSAfskq$VNi%W5QNExUZK8zJClzc#6~snT^fHM<Lvi`
ziJ~$tDj}%^e$^gG#mFR38{rI`|Mdu38E4||2M}wyXV<Igo-WIaCpmNMLtM#XO|nsp
zLydv3S_w3%bEBygwuFX&8qfK;Pf=T@y7oRqgb)Iq#sc#{9L6d*TTTjABq>9=2@_fY
z6~Rc-6U4ZL1zRF=5f|n@qqX!GgqXN_iF3z3!r&>D%f0eUvUjMt853$+1t#e|s;<}R
zA`9J)=fd$XSi5yU7k`^YeG6BvTsN%LM2MQzc>qWZDAMl(HX1AuB86@oxcJNGs4BKn
z9%$3_T6EF}Os->(#z0sx3o;r9hK)0U2$w&U^qwaZMU2H5H}WtNKs;bf)__1|5WtO&
zW%;=fLO{eIB3U2M^q-*!fC5p{1d|LjUDT|bNkMRBC_pt9m7WA8pbf;s00`iKF;6lJ
zk}^sMV8%dNc73)bFU{aLNgu%4Y#5ED5Pb&KuE@R&Ok}Cps76$CM9l`aTptK9Ffz0A
zQ|RH#-HWXOLP&5<09~Myu`mokH3T@b@DKPHSGogJa+pfJcTx#yge?2s@AOC}IUm5n
z=|3_Csz4KH3<F?*2+&rSqn~_p_E81Cox6evoId$hFL?%t$e)B(9MM9bs78yUna9#t
zot0jWfO^Wpt^6zlOQ{)i05nCWw-|s=>GuHt0$Pu(QF_|%DF6Tf07*qoM6N<$f<-z$
A=l}o!
--- a/toolkit/themes/gnomestripe/mozapps/extensions/extensions.css
+++ b/toolkit/themes/gnomestripe/mozapps/extensions/extensions.css
@@ -248,16 +248,19 @@
   list-style-image: url("chrome://mozapps/skin/extensions/category-extensions.png");
 }
 #category-theme > .category-icon {
   list-style-image: url("chrome://mozapps/skin/extensions/category-themes.png");
 }
 #category-plugin > .category-icon {
   list-style-image: url("chrome://mozapps/skin/extensions/category-plugins.png");
 }
+#category-dictionary > .category-icon {
+  list-style-image: url("chrome://mozapps/skin/extensions/category-dictionaries.png");
+}
 #category-availableUpdates > .category-icon {
   list-style-image: url("chrome://mozapps/skin/extensions/category-available.png");
 }
 #category-recentUpdates > .category-icon {
   list-style-image: url("chrome://mozapps/skin/extensions/category-recent.png");
 }
 
 
@@ -429,16 +432,20 @@
 .addon-view[type="locale"] .icon {
   list-style-image: url("chrome://mozapps/skin/extensions/localeGeneric.png");
 }
 
 .addon-view[type="plugin"] .icon {
   list-style-image: url("chrome://mozapps/skin/plugins/pluginGeneric.png");
 }
 
+.addon-view[type="dictionary"] .icon {
+  list-style-image: url("chrome://mozapps/skin/extensions/dictionaryGeneric.png");
+}
+
 .name-container {
   font-size: 150%;
   margin-bottom: 0;
   font-weight: bold;
   -moz-box-align: end;
   -moz-box-flex: 1;
 }
 
--- a/toolkit/themes/gnomestripe/mozapps/extensions/newaddon.css
+++ b/toolkit/themes/gnomestripe/mozapps/extensions/newaddon.css
@@ -78,16 +78,20 @@
 .addon-info[type="locale"] #icon {
   list-style-image: url("chrome://mozapps/skin/extensions/localeGeneric.png");
 }
 
 .addon-info[type="plugin"] #icon {
   list-style-image: url("chrome://mozapps/skin/plugins/pluginGeneric.png");
 }
 
+.addon-info[type="dictionary"] #icon {
+  list-style-image: url("chrome://mozapps/skin/plugins/dictionaryGeneric.png");
+}
+
 #name {
   font-size: 130%;
 }
 
 #author {
   color: GrayText;
 }
 
--- a/toolkit/themes/gnomestripe/mozapps/extensions/selectAddons.css
+++ b/toolkit/themes/gnomestripe/mozapps/extensions/selectAddons.css
@@ -153,16 +153,20 @@
 .addon-icon[type="theme"] {
   list-style-image: url("chrome://mozapps/skin/extensions/themeGeneric-16.png");
 }
 
 .addon-icon[type="plugin"] {
   list-style-image: url("chrome://mozapps/skin/plugins/pluginGeneric-16.png");
 }
 
+.addon-icon[type="dictionary"] {
+  list-style-image: url("chrome://mozapps/skin/extensions/dictionaryGeneric-16.png");
+}
+
 .action-list {
   margin-top: 10px;
   -moz-margin-start: 5em;
 }
 
 .action-header {
   margin-bottom: 10px;
 }
--- a/toolkit/themes/gnomestripe/mozapps/jar.mn
+++ b/toolkit/themes/gnomestripe/mozapps/jar.mn
@@ -6,21 +6,24 @@ toolkit.jar:
 + skin/classic/mozapps/extensions/extensions.svg           (extensions/extensions.svg)
 + skin/classic/mozapps/extensions/category-search.png      (extensions/category-search.png)
 + skin/classic/mozapps/extensions/category-discover.png    (extensions/category-discover.png)
 + skin/classic/mozapps/extensions/category-languages.png   (extensions/category-languages.png)
 + skin/classic/mozapps/extensions/category-searchengines.png (extensions/category-searchengines.png)
 + skin/classic/mozapps/extensions/category-extensions.png  (extensions/category-extensions.png)
 + skin/classic/mozapps/extensions/category-themes.png      (extensions/category-themes.png)
 + skin/classic/mozapps/extensions/category-plugins.png     (extensions/category-plugins.png)
++ skin/classic/mozapps/extensions/category-dictionaries.png (extensions/category-dictionaries.png)
 + skin/classic/mozapps/extensions/category-recent.png      (extensions/category-recent.png)
 + skin/classic/mozapps/extensions/category-available.png   (extensions/category-available.png)
 + skin/classic/mozapps/extensions/discover-logo.png        (extensions/discover-logo.png)
 + skin/classic/mozapps/extensions/extensionGeneric.png     (extensions/extensionGeneric.png)
 + skin/classic/mozapps/extensions/extensionGeneric-16.png  (extensions/extensionGeneric-16.png)
++ skin/classic/mozapps/extensions/dictionaryGeneric.png    (extensions/dictionaryGeneric.png)
++ skin/classic/mozapps/extensions/dictionaryGeneric-16.png (extensions/dictionaryGeneric-16.png)
 + skin/classic/mozapps/extensions/themeGeneric.png         (extensions/themeGeneric.png)
 + skin/classic/mozapps/extensions/themeGeneric-16.png      (extensions/themeGeneric-16.png)
 + skin/classic/mozapps/extensions/localeGeneric.png        (extensions/localeGeneric.png)
 + skin/classic/mozapps/extensions/rating-won.png           (extensions/rating-won.png)
 + skin/classic/mozapps/extensions/rating-not-won.png       (extensions/rating-not-won.png)
 + skin/classic/mozapps/extensions/cancel.png               (extensions/cancel.png)
 + skin/classic/mozapps/extensions/heart.png                (extensions/heart.png)
 + skin/classic/mozapps/extensions/stripes-warning.png      (extensions/stripes-warning.png)
--- a/toolkit/themes/pinstripe/mozapps/extensions/about.css
+++ b/toolkit/themes/pinstripe/mozapps/extensions/about.css
@@ -28,16 +28,20 @@
 #genericAbout[addontype="locale"] #extensionIcon {
   list-style-image: url("chrome://mozapps/skin/extensions/localeGeneric.png");
 }
 
 #genericAbout[addontype="plugin"] #extensionIcon {
   list-style-image: url("chrome://mozapps/skin/plugins/pluginGeneric.png");
 }
 
+#genericAbout[addontype="dictionary"] #extensionIcon {
+  list-style-image: url("chrome://mozapps/skin/extensions/dictionaryGeneric.png");
+}
+
 #extensionName {
   font-size: 200%;
   font-weight: bolder;
 }
 
 #extensionVersion {
   font-weight: bold;
 }
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..54ae4f93fc5c8179b44d062f61cae2bee4a652dc
GIT binary patch
literal 1769
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
LNkvXXu0mjfD_$)g
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..4ad1a1a8251b5b93eea10fa88e74d76916134b6d
GIT binary patch
literal 742
zc$@*|0vY{@P)<h;3K|Lk000e1NJLTq000mG000mO1^@s6AM^iV0000PbVXQnQ*UN;
zcVTj606}DLVr3vnZDD6+Qe|Oed2z{QJOBU!h)G02R5;6h)4^+8RTRhZ@4fHNOD1Vb
zV48{<otlEpqJ=^OF2vG}jGMYELcyi}6N20P9oY%~10sPUX`w}1N|PBEwjr$=Lx_s;
zC7t)~z2_VkGflHlfBW;{oO90&W=8ky+2Z5(FJGUv(bpon5S($T)5a78BWDHg$YRu4
z5B{|2Prlk1Zrr?mTLa^iGd_P=bT6N|di^7My&nIS?d|Oa+1<Ux#_+-3-d_C*Xw{?o
zgL?R={PxKY^xy4}%_xH>Wn+{w*_4=+B#Og*27J-)_fG)V#8|$wc%H+T4c*?`1n=<<
z)C_ZuCJ8T_M4ckr&wrf)+}73>CqPuga8%V1L28QZC|jNw6>&x(N+H5jYns9r0IsU4
zQ$Q4A$`lStSJ0j+D1rx#)B>9?4p^9<<;;Bh)jC|K(|HYuDaSF<h~f*_KN^9-Tj%E3
ze7etvpMK8Py*o%c!ufH{^78U2K$I*(lQMOk32$CPeBjRa_jvE-EqY5Ak-rak_V7M2
z34mK$TRSy^D53@q8Wk=sEivD{!1={4ix-yodGMGY@2)dFJ4aRnaI34UuK{o*5n>dQ
z7&{Nv>0Z0RxrH~_-+9X5yKl%@i8<pO|I$Iq#GJ^gG+D^14DYVfy|Tj2=0m{nML`{f
zm=wVE`~4GuC`OZnY)Umsw5I}Dm1mFcV`d~(z-YBg#;-U|0LZE>Q0kNsHN@cXxWOE>
z3P;X{dBeLfnb(t5TZ6%13?z{m)$ylsKH$reP<TX?5Iij$YKC_XRYgQeA~P#1D-%F<
zPNDweujA<u3VwRNJ896sz&S7ns*{CzH%h8=C#M{||7EaOUGtN&;ctihUvymadsS8Z
Y1CxPmMBMCcTL1t607*qoM6N<$f+y->sQ>@~
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..54ae4f93fc5c8179b44d062f61cae2bee4a652dc
GIT binary patch
literal 1769
zc$@+01{V2=P)<h;3K|Lk000e1NJLTq001BW001Be1^@s6b9#F80000PbVXQnQ*UN;
zcVTj606}DLVr3vnZDD6+Qe|Oed2z{QJOBU&i%CR5R2Uh>!Ck9eR~5(M-xzbQz4u9S
z^3ulEXb`I)L?QUr3sHok)`F--Y<<Ci=)E68KY+L1dg+DUNwp}NYE_C_h@z$zOWUMP
z+oV079JBXYbB^)%v=-8?Q!hls=Yjt-<KH;7y}d9P00+Ym0wgfN93=J$FhEF#8>D!Z
zFf$~Y8SR<t*MphL8#uMST|fJgvmd-|sqek8yLWnfYr*lY1@C?HQA%;l!OWSaj+rBa
zsRctV>}^IQQA%MmPE0Af4L|wj_aFH*5X@BGfWhL}%D?mc@pqg)bJzP>tyaA3Y5sFh
zKKUd^u08&7GX`M8j4^X+d%K>y=R;qvM~;2>^qqHc=FA!X8{;_g$iwH^y7<tizWu--
z9(?BdZs#>BGX{&*!oG2$thsdl2kiZRo0GSm;OtvYuv~4iS{+8EA~UQM5|E&`PV|X3
zZs@%ez0t-sx!G{GPqaJU{w?Fe&w<WsR1PZ7UB3LD^`i2ZXLh*#_+ef;wBWWIw=<Yg
zs$=H38JnpiB>`;40K{S_j4g;1p+GV=t%KXUfx=AXAYZTB>g3kI;Z<QZ!11lhEr(aQ
zL>(&819#XOmh?zcVpTfk&U({0v{<m78r7Zk*eK?Nv=VY=oCAy$Og)GUBrq4l;2b@=
zMKz<8LMD)6wJelk47DJM;stXsODx5r6c)8m%n`<%Gb3c~0znr{J=hyN3eh&5Qk`XS
zmdgPH#xX!f8#}#sQk~4CnB&D+E(XlR%N&fE%8X&O5ax#CB#?+`L0t}HLW@ochDD)o
zI+@9#!wbePG6QfnZuEej9djqt5eGR3$c9qrN+LUCQq8DCWhezHFf&r3w_vD_xiO9%
zBzg;`o`66Bh@ljscfgDp=Ky2s9YvB7l4xB-Pi|~BOih><7DFK=#@4BB42z0@olWDh
zXRjfNS}ICo>K!l)G3U%kvMEH5K){qDNxT}EQ{CuOqa~O-r4~YvDfTvv_4X;w-hD3@
zFYho;6R!|hF))mo%8VJf!x$nXDF&M<*|f&8tmq2<{M;^YI=14(p(VxP#=5h!9(kc0
z<8xp68f6&JwBe--4>Pq+9SS}<5(hX3S%xr)o?_~WnIMfG$;B%>yz|4KU}trbtJl}8
zH=P?(=SnR3%(<_FiD-@ORi#S|L*XBri77e;#*8x~pk>lSq#!eyB1w{UYus_?M>+Gp
z5Ad;j@8{Wmm@B(Cczidw=ZohkZuDv7=|4Tn6Tdl+AyQ&d3n|`^Gh<*faEFvg2^R<>
zGC8^$h(6)KC-3_LSM3OQ-}fa}%PrbC^1>63@z;lbL@m%$^bk`|q9-YgnaYd=t&1rI
z5<SJ(gU!@AvRd%$g<qpmIC;mr7;543=f29+gEns1z4|<V{OJ#=MWhT9`wRzC!i)nd
zbA}ZINpvM<Mo3^zNYr9n`rR*(IVaxwHZlYz{(kL6E}nk?L%3jyPASgRlSIf9Nydyb
z<7R}CsRaUhBxVpPrk<q09RBvmd9FVF6nz@md+9|k{_;T-4L6t~$b=>#K!Oaz%$Rd#
zBv}L$1CxV^X$o$P6I1K76gSolGI-**=ec_MDK7l%$5<ax24yH<P6#rS-UAGf*k{aC
zW`rQcC?SH(0tJK-z`~%`!q@@`E<O4yvUR!%b7!-jkUKaijTF>Ukb{{qSDA4$3ljy=
zLWH12kV<+tcG^TOMsa8X%0v-_8yN}i^d4ja7EB>hf#IZN%v5GlLMb8=l%$dfCj@fQ
zn=msnp+#UA6h{(c?+mpvMNo^=yWu7>o!%$hIKX*5OQ{-0OQCdnPs|+&#wqBT^n?&B
zmW5$qNU&*1NVMoIYDE~Sq<AGIaOkND7_U*e$$-)#S4sf|+>o4%WXjH9j+a72;BIUt
zAwfjq4hkbfNJ0`R=zYR4qKTfd0tyg-*yr42z^Y|#H$+CzGjU6LBoTpt);jB+Opzdn
zOd_H8q)FgTD3B$!7={r_y2KQ@4Xgm;Rh63xa40fvsb-{jg#dE{3gEcI(v4|qU{Fh?
zWdp=e9LYe?y9g!AVSor~fylfCI0TG9vafPe0S-sXQ+8=gJKa09tn5w3m7O(<>P*p*
zU^!G$Nik>Y!Qce}Jpv4BskCTBj;!i{yk3ix14n>eps~-mX$!c$y5CyekGR>us{|Ne
zfB*^1c!l^E<Mjj>H>K2i=3dXd20RC>*=OA3zzV4RZ*^b;B>Vmel%Pwalwo+K00000
LNkvXXu0mjfD_$)g
--- a/toolkit/themes/pinstripe/mozapps/extensions/eula.css
+++ b/toolkit/themes/pinstripe/mozapps/extensions/eula.css
@@ -12,16 +12,20 @@
 #eula-dialog[addontype="locale"] #icon {
   list-style-image: url("chrome://mozapps/skin/extensions/localeGeneric.png");
 }
 
 #eula-dialog[addontype="plugin"] #icon {
   list-style-image: url("chrome://mozapps/skin/plugins/pluginGeneric.png");
 }
 
+#eula-dialog[addontype="dictionary"] #icon {
+  list-style-image: url("chrome://mozapps/skin/extensions/dictionaryGeneric.png");
+}
+
 #heading-container {
   -moz-box-align: center;
 }
 
 #heading {
   font-size: 120%;
 }
 
--- a/toolkit/themes/pinstripe/mozapps/extensions/extensions.css
+++ b/toolkit/themes/pinstripe/mozapps/extensions/extensions.css
@@ -281,16 +281,19 @@
   list-style-image: url("chrome://mozapps/skin/extensions/category-extensions.png");
 }
 #category-theme > .category-icon {
   list-style-image: url("chrome://mozapps/skin/extensions/category-themes.png");
 }
 #category-plugin > .category-icon {
   list-style-image: url("chrome://mozapps/skin/extensions/category-plugins.png");
 }
+#category-dictionary > .category-icon {
+  list-style-image: url("chrome://mozapps/skin/extensions/category-dictionaries.png");
+}
 #category-availableUpdates > .category-icon {
   list-style-image: url("chrome://mozapps/skin/extensions/category-available.png");
 }
 #category-recentUpdates > .category-icon {
   list-style-image: url("chrome://mozapps/skin/extensions/category-recent.png");
 }
 
 
@@ -494,16 +497,20 @@
 .addon-view[type="locale"] .icon {
   list-style-image: url("chrome://mozapps/skin/extensions/localeGeneric.png");
 }
 
 .addon-view[type="plugin"] .icon {
   list-style-image: url("chrome://mozapps/skin/plugins/pluginGeneric.png");
 }
 
+.addon-view[type="dictionary"] .icon {
+  list-style-image: url("chrome://mozapps/skin/extensions/dictionaryGeneric.png");
+}
+
 .name-container {
   font-size: 150%;
   margin-bottom: 0;
   font-weight: bold;
   color: #000;
   text-shadow: @loweredShadow@;
   -moz-box-align: end;
   -moz-box-flex: 1;
--- a/toolkit/themes/pinstripe/mozapps/extensions/newaddon.css
+++ b/toolkit/themes/pinstripe/mozapps/extensions/newaddon.css
@@ -80,16 +80,20 @@
 .addon-info[type="locale"] #icon {
   list-style-image: url("chrome://mozapps/skin/extensions/localeGeneric.png");
 }
 
 .addon-info[type="plugin"] #icon {
   list-style-image: url("chrome://mozapps/skin/plugins/pluginGeneric.png");
 }
 
+.addon-info[type="dictionary"] #icon {
+  list-style-image: url("chrome://mozapps/skin/plugins/dictionaryGeneric.png");
+}
+
 #name {
   font-size: 130%;
 }
 
 #author {
   color: GrayText;
 }
 
--- a/toolkit/themes/pinstripe/mozapps/extensions/selectAddons.css
+++ b/toolkit/themes/pinstripe/mozapps/extensions/selectAddons.css
@@ -152,16 +152,20 @@
 .addon-icon[type="theme"] {
   list-style-image: url("chrome://mozapps/skin/extensions/themeGeneric-16.png");
 }
 
 .addon-icon[type="plugin"] {
   list-style-image: url("chrome://mozapps/skin/plugins/pluginGeneric-16.png");
 }
 
+.addon-icon[type="dictionary"] {
+  list-style-image: url("chrome://mozapps/skin/extensions/dictionaryGeneric-16.png");
+}
+
 .action-list {
   margin-top: 10px;
   -moz-margin-start: 5em;
 }
 
 .action-header {
   margin-bottom: 10px;
 }
--- a/toolkit/themes/pinstripe/mozapps/jar.mn
+++ b/toolkit/themes/pinstripe/mozapps/jar.mn
@@ -7,23 +7,26 @@ toolkit.jar:
   skin/classic/mozapps/downloads/unknownContentType.css           (downloads/unknownContentType.css)
   skin/classic/mozapps/extensions/category-search.png             (extensions/category-search.png)
   skin/classic/mozapps/extensions/category-discover.png           (extensions/category-discover.png)
   skin/classic/mozapps/extensions/category-languages.png          (extensions/category-languages.png)
   skin/classic/mozapps/extensions/category-searchengines.png      (extensions/category-searchengines.png)
   skin/classic/mozapps/extensions/category-extensions.png         (extensions/category-extensions.png)
   skin/classic/mozapps/extensions/category-themes.png             (extensions/category-themes.png)
   skin/classic/mozapps/extensions/category-plugins.png            (extensions/category-plugins.png)
+  skin/classic/mozapps/extensions/category-dictionaries.png       (extensions/category-dictionaries.png)
   skin/classic/mozapps/extensions/category-recent.png             (extensions/category-recent.png)
   skin/classic/mozapps/extensions/category-available.png          (extensions/category-available.png)
   skin/classic/mozapps/extensions/discover-logo.png               (extensions/discover-logo.png)
   skin/classic/mozapps/extensions/extensionGeneric.png            (extensions/extensionGeneric.png)
   skin/classic/mozapps/extensions/extensionGeneric-16.png         (extensions/extensionGeneric-16.png)
   skin/classic/mozapps/extensions/themeGeneric.png                (extensions/themeGeneric.png)
   skin/classic/mozapps/extensions/themeGeneric-16.png             (extensions/themeGeneric-16.png)
+  skin/classic/mozapps/extensions/dictionaryGeneric.png           (extensions/dictionaryGeneric.png)
+  skin/classic/mozapps/extensions/dictionaryGeneric-16.png        (extensions/dictionaryGeneric-16.png)
   skin/classic/mozapps/extensions/localeGeneric.png               (extensions/localeGeneric.png)
   skin/classic/mozapps/extensions/rating-won.png                  (extensions/rating-won.png)
   skin/classic/mozapps/extensions/rating-not-won.png              (extensions/rating-not-won.png)
   skin/classic/mozapps/extensions/cancel.png                      (extensions/cancel.png)
   skin/classic/mozapps/extensions/utilities.png                   (extensions/utilities.png)
   skin/classic/mozapps/extensions/toolbarbutton-dropmarker.png    (extensions/toolbarbutton-dropmarker.png)
   skin/classic/mozapps/extensions/heart.png                       (extensions/heart.png)
   skin/classic/mozapps/extensions/navigation.png                  (extensions/navigation.png)
--- a/toolkit/themes/pinstripe/mozapps/xpinstall/xpinstallConfirm.css
+++ b/toolkit/themes/pinstripe/mozapps/xpinstall/xpinstallConfirm.css
@@ -75,8 +75,12 @@ installitem[type="theme"] .xpinstallItem
 
 installitem[type="locale"] .xpinstallItemIcon {
   list-style-image: url("chrome://mozapps/skin/extensions/localeGeneric.png");
 }
 
 installitem[type="plugin"] .xpinstallItemIcon {
   list-style-image: url("chrome://mozapps/skin/plugins/pluginGeneric.png");
 }
+
+installitem[type="dictionary"] .xpinstallItemIcon {
+  list-style-image: url("chrome://mozapps/skin/extensions/dictionaryGeneric.png");
+}
--- a/toolkit/themes/winstripe/mozapps/extensions/about.css
+++ b/toolkit/themes/winstripe/mozapps/extensions/about.css
@@ -40,16 +40,20 @@
 #genericAbout[addontype="locale"] #extensionIcon {
   list-style-image: url("chrome://mozapps/skin/extensions/localeGeneric.png");
 }
 
 #genericAbout[addontype="plugin"] #extensionIcon {
   list-style-image: url("chrome://mozapps/skin/plugins/pluginGeneric.png");
 }
 
+#genericAbout[addontype="dictionary"] #extensionIcon {
+  list-style-image: url("chrome://mozapps/skin/extensions/dictionaryGeneric.png");
+}
+
 #extensionName {
   font-size: 200%;
   font-weight: bolder;
 }
 
 #extensionVersion {
   font-weight: bold;
 }
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..b26bb7100c8c3935ca0bec4218648a1085f43651
GIT binary patch
literal 1665
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
LNkvXXu0mjf;=v83
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..b26bb7100c8c3935ca0bec4218648a1085f43651
GIT binary patch
literal 1665
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
LNkvXXu0mjf;=v83
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..37e2a5e4ce0b6b2f6f7b668e321a244c6901bb00
GIT binary patch
literal 733
zc$@*<0wVp1P)<h;3K|Lk000e1NJLTq000mG000mO1^@s6AM^iV0000PbVXQnQ*UN;
zcVTj606}DLVr3vnZDD6+Qe|Oed2z{QJOBU!e@R3^R5(wCkvnf(RTPE4eeS)U_gK!5
z!HR=zP$;4(gomgAi3Tb}MTAmOQ}6>QkoXVj5<wsF8zLc4q?Dit<i?1C@i=yrc%Jv(
zbI#s}Vz9AfBv!SX^=YrQB&Ebwzn^{m>5UI|+u;F8hl{M>?VAHy1xQqq2C@_(1S%hn
zo;=My|ML62pFX*B$8uI$+v?aie|E3;`nNt}dwZJ^|E>M~{oz3veFl4v$K!D&$$Pd2
zgZ}+5-a7J88{<jMhacZ$t#D)xh#sqJP!DyDXpN*$zxVAg!*_OP(;NXnyvD}Woh!tr
zQ?9<YLA%o<i9?bh$&>0CDa_HugunKlHDKjDjUW~c1ggb?EO-bdS+<6$M?%1PkCg#w
zwm=*g0CiA&2ndj}f~?hrtbkgW%uA+6Gx|lO*J_edIs>><fNCVvo)81LjL9N$Jgq3T
z;P|9s@cviKiXG-lk8mFFPY0HisES7A<i&)gyiC6FCPxP&HgDagGkl%iD{rt|%<;?R
z#RxtqF$UC><;iod+_*-2^E%D;2CYlG%>H=9;m_Z(v)ki&@E0Q_t?_k<uPS<(GJbTQ
za{Po=?=t1#ZyY?l%di85)NrnYvk$5=5Pd||=sHhBBBO_Q*?jjlhmU_?&<d<K6BcS>
zi01&S4yY{=qN2&L`Hc1TCbAYe{P7-xZcbMWt0L0OagsPy4iL?X48w<jYQkwnoCeyG
zc=eJasRvb@2qZyd<v9Zc)wWr})Q}=4b%nesSOVt+qyWpo391RRL{M%23oz>iOXX;M
z(wcb3@4pI-!U2iZ<aTz807x0kdH|Btv(f2aHhAfDlK+zd4xYVOOppHt)74(A3C78<
P00000NkvXXu0mjfXQEkA
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..37e2a5e4ce0b6b2f6f7b668e321a244c6901bb00
GIT binary patch
literal 733
zc$@*<0wVp1P)<h;3K|Lk000e1NJLTq000mG000mO1^@s6AM^iV0000PbVXQnQ*UN;
zcVTj606}DLVr3vnZDD6+Qe|Oed2z{QJOBU!e@R3^R5(wCkvnf(RTPE4eeS)U_gK!5
z!HR=zP$;4(gomgAi3Tb}MTAmOQ}6>QkoXVj5<wsF8zLc4q?Dit<i?1C@i=yrc%Jv(
zbI#s}Vz9AfBv!SX^=YrQB&Ebwzn^{m>5UI|+u;F8hl{M>?VAHy1xQqq2C@_(1S%hn
zo;=My|ML62pFX*B$8uI$+v?aie|E3;`nNt}dwZJ^|E>M~{oz3veFl4v$K!D&$$Pd2
zgZ}+5-a7J88{<jMhacZ$t#D)xh#sqJP!DyDXpN*$zxVAg!*_OP(;NXnyvD}Woh!tr
zQ?9<YLA%o<i9?bh$&>0CDa_HugunKlHDKjDjUW~c1ggb?EO-bdS+<6$M?%1PkCg#w
zwm=*g0CiA&2ndj}f~?hrtbkgW%uA+6Gx|lO*J_edIs>><fNCVvo)81LjL9N$Jgq3T
z;P|9s@cviKiXG-lk8mFFPY0HisES7A<i&)gyiC6FCPxP&HgDagGkl%iD{rt|%<;?R
z#RxtqF$UC><;iod+_*-2^E%D;2CYlG%>H=9;m_Z(v)ki&@E0Q_t?_k<uPS<(GJbTQ
za{Po=?=t1#ZyY?l%di85)NrnYvk$5=5Pd||=sHhBBBO_Q*?jjlhmU_?&<d<K6BcS>
zi01&S4yY{=qN2&L`Hc1TCbAYe{P7-xZcbMWt0L0OagsPy4iL?X48w<jYQkwnoCeyG
zc=eJasRvb@2qZyd<v9Zc)wWr})Q}=4b%nesSOVt+qyWpo391RRL{M%23oz>iOXX;M
z(wcb3@4pI-!U2iZ<aTz807x0kdH|Btv(f2aHhAfDlK+zd4xYVOOppHt)74(A3C78<
P00000NkvXXu0mjfXQEkA
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..b26bb7100c8c3935ca0bec4218648a1085f43651
GIT binary patch
literal 1665
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
LNkvXXu0mjf;=v83
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..b26bb7100c8c3935ca0bec4218648a1085f43651
GIT binary patch
literal 1665
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
LNkvXXu0mjf;=v83
--- a/toolkit/themes/winstripe/mozapps/extensions/eula.css
+++ b/toolkit/themes/winstripe/mozapps/extensions/eula.css
@@ -12,16 +12,20 @@
 #eula-dialog[addontype="locale"] #icon {
   list-style-image: url("chrome://mozapps/skin/extensions/localeGeneric.png");
 }
 
 #eula-dialog[addontype="plugin"] #icon {
   list-style-image: url("chrome://mozapps/skin/plugins/pluginGeneric.png");
 }
 
+#eula-dialog[addontype="dictionary"] #icon {
+  list-style-image: url("chrome://mozapps/skin/extensions/dictionaryGeneric.png");
+}
+
 #heading-container {
   -moz-box-align: center;
 }
 
 #heading {
   font-size: 120%;
 }
 
--- a/toolkit/themes/winstripe/mozapps/extensions/extensions.css
+++ b/toolkit/themes/winstripe/mozapps/extensions/extensions.css
@@ -293,16 +293,19 @@
   list-style-image: url("chrome://mozapps/skin/extensions/category-extensions.png");
 }
 #category-theme > .category-icon {
   list-style-image: url("chrome://mozapps/skin/extensions/category-themes.png");
 }
 #category-plugin > .category-icon {
   list-style-image: url("chrome://mozapps/skin/extensions/category-plugins.png");
 }
+#category-dictionary > .category-icon {
+  list-style-image: url("chrome://mozapps/skin/extensions/category-dictionaries.png");
+}
 #category-availableUpdates > .category-icon {
   list-style-image: url("chrome://mozapps/skin/extensions/category-available.png");
 }
 #category-recentUpdates > .category-icon {
   list-style-image: url("chrome://mozapps/skin/extensions/category-recent.png");
 }
 
 
@@ -487,16 +490,20 @@
 .addon-view[type="locale"] .icon {
   list-style-image: url("chrome://mozapps/skin/extensions/localeGeneric.png");
 }
 
 .addon-view[type="plugin"] .icon {
   list-style-image: url("chrome://mozapps/skin/plugins/pluginGeneric.png");
 }
 
+.addon-view[type="dictionary"] .icon {
+  list-style-image: url("chrome://mozapps/skin/extensions/dictionaryGeneric.png");
+}
+
 .name-container {
   font-size: 150%;
   font-weight: bold;
   color: #3F3F3F;
   margin-bottom: 0;
   -moz-box-align: end;
   -moz-box-flex: 1;
 }
--- a/toolkit/themes/winstripe/mozapps/extensions/newaddon.css
+++ b/toolkit/themes/winstripe/mozapps/extensions/newaddon.css
@@ -78,16 +78,20 @@
 .addon-info[type="locale"] #icon {
   list-style-image: url("chrome://mozapps/skin/extensions/localeGeneric.png");
 }
 
 .addon-info[type="plugin"] #icon {
   list-style-image: url("chrome://mozapps/skin/plugins/pluginGeneric.png");
 }
 
+.addon-info[type="dictionary"] #icon {
+  list-style-image: url("chrome://mozapps/skin/plugins/dictionaryGeneric.png");
+}
+
 #name {
   font-size: 130%;
 }
 
 #author {
   color: GrayText;
 }
 
--- a/toolkit/themes/winstripe/mozapps/extensions/selectAddons.css
+++ b/toolkit/themes/winstripe/mozapps/extensions/selectAddons.css
@@ -165,16 +165,20 @@
 .addon-icon[type="theme"] {
   list-style-image: url("chrome://mozapps/skin/extensions/themeGeneric-16.png");
 }
 
 .addon-icon[type="plugin"] {
   list-style-image: url("chrome://mozapps/skin/plugins/pluginGeneric-16.png");
 }
 
+.addon-icon[type="dictionary"] {
+  list-style-image: url("chrome://mozapps/skin/extensions/dictionaryGeneric-16.png");
+}
+
 .action-list {
   margin-top: 10px;
   -moz-margin-start: 5em;
 }
 
 .action-header {
   margin-bottom: 10px;
 }
--- a/toolkit/themes/winstripe/mozapps/jar.mn
+++ b/toolkit/themes/winstripe/mozapps/jar.mn
@@ -15,23 +15,26 @@ toolkit.jar:
         skin/classic/mozapps/extensions/extensions.svg             (extensions/extensions.svg)
         skin/classic/mozapps/extensions/category-search.png        (extensions/category-search.png)
         skin/classic/mozapps/extensions/category-discover.png      (extensions/category-discover.png)
         skin/classic/mozapps/extensions/category-languages.png     (extensions/category-languages.png)
         skin/classic/mozapps/extensions/category-searchengines.png (extensions/category-searchengines.png)
         skin/classic/mozapps/extensions/category-extensions.png    (extensions/category-extensions.png)
         skin/classic/mozapps/extensions/category-themes.png        (extensions/category-themes.png)
         skin/classic/mozapps/extensions/category-plugins.png       (extensions/category-plugins.png)
+        skin/classic/mozapps/extensions/category-dictionaries.png  (extensions/category-dictionaries.png)
         skin/classic/mozapps/extensions/category-recent.png        (extensions/category-recent.png)
         skin/classic/mozapps/extensions/category-available.png     (extensions/category-available.png)
         skin/classic/mozapps/extensions/discover-logo.png          (extensions/discover-logo.png)
         skin/classic/mozapps/extensions/extensionGeneric.png       (extensions/extensionGeneric.png)
         skin/classic/mozapps/extensions/extensionGeneric-16.png    (extensions/extensionGeneric-16.png)
         skin/classic/mozapps/extensions/themeGeneric.png           (extensions/themeGeneric.png)
         skin/classic/mozapps/extensions/themeGeneric-16.png        (extensions/themeGeneric-16.png)
+        skin/classic/mozapps/extensions/dictionaryGeneric.png      (extensions/dictionaryGeneric.png)
+        skin/classic/mozapps/extensions/dictionaryGeneric-16.png   (extensions/dictionaryGeneric-16.png)
         skin/classic/mozapps/extensions/localeGeneric.png          (extensions/localeGeneric.png)
         skin/classic/mozapps/extensions/rating-won.png             (extensions/rating-won.png)
         skin/classic/mozapps/extensions/rating-not-won.png         (extensions/rating-not-won.png)
         skin/classic/mozapps/extensions/cancel.png                 (extensions/cancel.png)
         skin/classic/mozapps/extensions/utilities.png              (extensions/utilities.png)
         skin/classic/mozapps/extensions/heart.png                  (extensions/heart.png)
         skin/classic/mozapps/extensions/navigation.png             (extensions/navigation.png)
         skin/classic/mozapps/extensions/stripes-warning.png        (extensions/stripes-warning.png)
@@ -92,23 +95,26 @@ toolkit.jar:
         skin/classic/aero/mozapps/extensions/themeGeneric.png              (extensions/themeGeneric-aero.png)
         skin/classic/aero/mozapps/extensions/category-search.png           (extensions/category-search.png)
         skin/classic/aero/mozapps/extensions/category-discover.png         (extensions/category-discover-aero.png)
         skin/classic/aero/mozapps/extensions/category-languages.png        (extensions/category-languages-aero.png)
         skin/classic/aero/mozapps/extensions/category-searchengines.png    (extensions/category-searchengines.png)
         skin/classic/aero/mozapps/extensions/category-extensions.png       (extensions/category-extensions-aero.png)
         skin/classic/aero/mozapps/extensions/category-themes.png           (extensions/category-themes-aero.png)
         skin/classic/aero/mozapps/extensions/category-plugins.png          (extensions/category-plugins-aero.png)
+        skin/classic/aero/mozapps/extensions/category-dictionaries.png     (extensions/category-dictionaries-aero.png)
         skin/classic/aero/mozapps/extensions/category-recent.png           (extensions/category-recent-aero.png)
         skin/classic/aero/mozapps/extensions/category-available.png        (extensions/category-available-aero.png)
         skin/classic/aero/mozapps/extensions/discover-logo.png             (extensions/discover-logo.png)
         skin/classic/aero/mozapps/extensions/extensionGeneric.png          (extensions/extensionGeneric-aero.png)
         skin/classic/aero/mozapps/extensions/extensionGeneric-16.png       (extensions/extensionGeneric-16-aero.png)
         skin/classic/aero/mozapps/extensions/themeGeneric.png              (extensions/themeGeneric-aero.png)
         skin/classic/aero/mozapps/extensions/themeGeneric-16.png           (extensions/themeGeneric-16-aero.png)
+        skin/classic/aero/mozapps/extensions/dictionaryGeneric.png         (extensions/dictionaryGeneric-aero.png)
+        skin/classic/aero/mozapps/extensions/dictionaryGeneric-16.png      (extensions/dictionaryGeneric-16-aero.png)
         skin/classic/aero/mozapps/extensions/localeGeneric.png             (extensions/localeGeneric-aero.png)
         skin/classic/aero/mozapps/extensions/rating-won.png                (extensions/rating-won.png)
         skin/classic/aero/mozapps/extensions/rating-not-won.png            (extensions/rating-not-won.png)
         skin/classic/aero/mozapps/extensions/cancel.png                    (extensions/cancel.png)
         skin/classic/aero/mozapps/extensions/utilities.png                 (extensions/utilities.png)
         skin/classic/aero/mozapps/extensions/heart.png                     (extensions/heart.png)
         skin/classic/aero/mozapps/extensions/navigation.png                (extensions/navigation.png)
         skin/classic/aero/mozapps/extensions/stripes-warning.png           (extensions/stripes-warning.png)
--- a/toolkit/themes/winstripe/mozapps/xpinstall/xpinstallConfirm.css
+++ b/toolkit/themes/winstripe/mozapps/xpinstall/xpinstallConfirm.css
@@ -86,8 +86,12 @@ installitem[type="theme"] .xpinstallItem
 
 installitem[type="locale"] .xpinstallItemIcon {
   list-style-image: url("chrome://mozapps/skin/extensions/localeGeneric.png");
 }
 
 installitem[type="plugin"] .xpinstallItemIcon {
   list-style-image: url("chrome://mozapps/skin/plugins/pluginGeneric.png");
 }
+
+installitem[type="dictionary"] .xpinstallItemIcon {
+  list-style-image: url("chrome://mozapps/skin/extensions/dictionaryGeneric.png");
+}