merge m-c to fx-team
authorTim Taubert <ttaubert@mozilla.com>
Mon, 05 Aug 2013 10:03:51 +0200
changeset 153540 6bc019d8abc824fd2671d9d62324438ab3dde70f
parent 153498 482b9d04974acd3a7687de3408bd7f6d73638e63 (current diff)
parent 153539 b36e521b71cd89ffd7ee0bf87a23aa07503f786e (diff)
child 153633 54434a926c5f2f8ff7506499a400ebb56d7ee2a6
push id2859
push userakeybl@mozilla.com
push dateMon, 16 Sep 2013 19:14:59 +0000
treeherdermozilla-beta@87d3c51cd2bf [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone25.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
merge m-c to fx-team
browser/devtools/shared/AutocompletePopup.jsm
browser/devtools/webconsole/HUDService.jsm
browser/devtools/webconsole/NetworkPanel.jsm
browser/devtools/webconsole/WebConsolePanel.jsm
browser/devtools/webconsole/test/browser_webconsole_bug_580400_groups.js
configure.in
toolkit/devtools/server/tests/unit/test_trace_actor-07.js
toolkit/devtools/webconsole/NetworkHelper.jsm
toolkit/devtools/webconsole/WebConsoleClient.jsm
toolkit/devtools/webconsole/WebConsoleUtils.jsm
--- a/browser/app/profile/firefox.js
+++ b/browser/app/profile/firefox.js
@@ -330,16 +330,19 @@ pref("browser.download.manager.showWhenS
 pref("browser.download.manager.closeWhenDone", false);
 pref("browser.download.manager.focusWhenStarting", false);
 pref("browser.download.manager.flashCount", 2);
 pref("browser.download.manager.addToRecentDocs", true);
 pref("browser.download.manager.quitBehavior", 0);
 pref("browser.download.manager.scanWhenDone", true);
 pref("browser.download.manager.resumeOnWakeDelay", 10000);
 
+// Enables the asynchronous Downloads API in the Downloads Panel.
+pref("browser.download.useJSTransfer", false);
+
 // This allows disabling the Downloads Panel in favor of the old interface.
 pref("browser.download.useToolkitUI", false);
 
 // This allows disabling the animated notifications shown by
 // the Downloads Indicator when a download starts or completes.
 pref("browser.download.animateNotifications", true);
 
 // This records whether or not the panel has been shown at least once.
--- a/browser/base/content/browser-sets.inc
+++ b/browser/base/content/browser-sets.inc
@@ -91,17 +91,17 @@
     <command id="Browser:RestoreLastSession" oncommand="restoreLastSession();" disabled="true"/>
 
     <command id="Tools:Search" oncommand="BrowserSearch.webSearch();"/>
     <command id="Tools:Downloads" oncommand="BrowserDownloadsUI();"/>
     <command id="Tools:DevToolbox" oncommand="gDevToolsBrowser.toggleToolboxCommand(gBrowser);"/>
     <command id="Tools:DevToolbar" oncommand="DeveloperToolbar.toggle();" disabled="true" hidden="true"/>
     <command id="Tools:DevToolbarFocus" oncommand="DeveloperToolbar.focusToggle();" disabled="true"/>
     <command id="Tools:ChromeDebugger" oncommand="BrowserDebuggerProcess.init();" disabled="true" hidden="true"/>
-    <command id="Tools:BrowserConsole" oncommand="HUDConsoleUI.toggleBrowserConsole();"/>
+    <command id="Tools:BrowserConsole" oncommand="HUDService.toggleBrowserConsole();"/>
     <command id="Tools:Scratchpad" oncommand="Scratchpad.openScratchpad();" disabled="true" hidden="true"/>
     <command id="Tools:ResponsiveUI" oncommand="ResponsiveUI.toggle();" disabled="true" hidden="true"/>
     <command id="Tools:Addons" oncommand="BrowserOpenAddonsMgr();"/>
     <command id="Tools:ErrorConsole" oncommand="toJavaScriptConsole()" disabled="true" hidden="true"/>
     <command id="Tools:DevToolsConnect" oncommand="gDevToolsBrowser.openConnectScreen(gBrowser)" disabled="true" hidden="true"/>
     <command id="Tools:Sanitize"
      oncommand="Cc['@mozilla.org/browser/browserglue;1'].getService(Ci.nsIBrowserGlue).sanitize(window);"/>
     <command id="Tools:PrivateBrowsing"
@@ -171,17 +171,18 @@
     <broadcaster id="workOfflineMenuitemState"/>
     <broadcaster id="socialSidebarBroadcaster" hidden="true"/>
     <broadcaster id="socialActiveBroadcaster" hidden="true"/>
 
     <!-- DevTools broadcasters -->
     <broadcaster id="devtoolsMenuBroadcaster_DevToolbox"
                  label="&devToolboxMenuItem.label;"
                  type="checkbox" autocheck="false"
-                 command="Tools:DevToolbox"/>
+                 command="Tools:DevToolbox"
+                 key="key_devToolboxMenuItem"/>
     <broadcaster id="devtoolsMenuBroadcaster_DevToolbar"
                  label="&devToolbarMenu.label;"
                  type="checkbox" autocheck="false"
                  command="Tools:DevToolbar"
                  key="key_devToolbar"/>
     <broadcaster id="devtoolsMenuBroadcaster_ChromeDebugger"
                  label="&chromeDebuggerMenu.label;"
                  command="Tools:ChromeDebugger"/>
@@ -256,26 +257,37 @@
 #endif
 #ifdef XP_GNOME
     <key id="key_search2" key="&searchFocusUnix.commandkey;" command="Tools:Search" modifiers="accel"/>
     <key id="key_openDownloads" key="&downloadsUnix.commandkey;" command="Tools:Downloads" modifiers="accel,shift"/>
 #else
     <key id="key_openDownloads" key="&downloads.commandkey;" command="Tools:Downloads" modifiers="accel"/>
 #endif
     <key id="key_openAddons" key="&addons.commandkey;" command="Tools:Addons" modifiers="accel,shift"/>
+    <key id="key_devToolboxMenuItemF12" keycode="&devToolsCmd.keycode;" keytext="&devToolsCmd.keytext;" command="Tools:DevToolbox"/>
     <key id="key_browserConsole" key="&browserConsoleCmd.commandkey;" command="Tools:BrowserConsole" modifiers="accel,shift"/>
     <key id="key_devToolbar" keycode="&devToolbar.keycode;" modifiers="shift"
          keytext="&devToolbar.keytext;" command="Tools:DevToolbarFocus"/>
     <key id="key_responsiveUI" key="&responsiveDesignTool.commandkey;" command="Tools:ResponsiveUI"
 #ifdef XP_MACOSX
         modifiers="accel,alt"
 #else
         modifiers="accel,shift"
 #endif
     />
+
+    <key id="key_devToolboxMenuItem" keycode="&devToolboxMenuItem.keycode;"
+         keytext="&devToolboxMenuItem.keytext;" command="Tools:DevToolbox" key="&devToolboxMenuItem.keytext;"
+#ifdef XP_MACOSX
+        modifiers="accel,alt"
+#else
+        modifiers="accel,shift"
+#endif
+    />
+
     <key id="key_scratchpad" keycode="&scratchpad.keycode;" modifiers="shift"
          keytext="&scratchpad.keytext;" command="Tools:Scratchpad"/>
     <key id="openFileKb" key="&openFileCmd.commandkey;" command="Browser:OpenFile"  modifiers="accel"/>
     <key id="key_savePage" key="&savePageCmd.commandkey;" command="Browser:SavePage" modifiers="accel"/>
     <key id="printKb" key="&printCmd.commandkey;" command="cmd_print"  modifiers="accel"/>
     <key id="key_close" key="&closeCmd.key;" command="cmd_close" modifiers="accel"/>
     <key id="key_closeWindow" key="&closeCmd.key;" command="cmd_closeWindow" modifiers="accel,shift"/>
     <key id="key_undo"
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -1101,17 +1101,25 @@ var gBrowserInit = {
     gPrefService.addObserver(ctrlTab.prefName, ctrlTab, false);
 
     // Initialize the download manager some time after the app starts so that
     // auto-resume downloads begin (such as after crashing or quitting with
     // active downloads) and speeds up the first-load of the download manager UI.
     // If the user manually opens the download manager before the timeout, the
     // downloads will start right away, and getting the service again won't hurt.
     setTimeout(function() {
-      Services.downloads;
+      let DownloadsCommon =
+        Cu.import("resource:///modules/DownloadsCommon.jsm", {}).DownloadsCommon;
+      if (DownloadsCommon.useJSTransfer) {
+        // Open the data link without initalizing nsIDownloadManager.
+        DownloadsCommon.initializeAllDataLinks();
+      } else {
+        // Initalizing nsIDownloadManager will trigger the data link.
+        Services.downloads;
+      }
       let DownloadTaskbarProgress =
         Cu.import("resource://gre/modules/DownloadTaskbarProgress.jsm", {}).DownloadTaskbarProgress;
       DownloadTaskbarProgress.onBrowserWindowLoad(window);
     }, 10000);
 
     // The object handling the downloads indicator is also initialized here in the
     // delayed startup function, but the actual indicator element is not loaded
     // unless there are downloads to be displayed.
@@ -7148,18 +7156,23 @@ var TabContextMenu = {
 };
 
 XPCOMUtils.defineLazyModuleGetter(this, "gDevTools",
                                   "resource:///modules/devtools/gDevTools.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "gDevToolsBrowser",
                                   "resource:///modules/devtools/gDevTools.jsm");
 
-XPCOMUtils.defineLazyGetter(this, "HUDConsoleUI", function () {
-  return Cu.import("resource:///modules/HUDService.jsm", {}).HUDService.consoleUI;
+Object.defineProperty(this, "HUDService", {
+  get: function HUDService_getter() {
+    let devtools = Cu.import("resource://gre/modules/devtools/Loader.jsm", {}).devtools;
+    return devtools.require("devtools/webconsole/hudservice");
+  },
+  configurable: true,
+  enumerable: true
 });
 
 // Prompt user to restart the browser in safe mode
 function safeModeRestart()
 {
   // prompt the user to confirm
   let promptTitle = gNavigatorBundle.getString("safeModeRestartPromptTitle");
   let promptMessage =
--- a/browser/base/content/browser.xul
+++ b/browser/base/content/browser.xul
@@ -1047,26 +1047,34 @@
     </vbox>
     <vbox id="browser-border-end" hidden="true" layer="true"/>
   </hbox>
 
   <hbox id="full-screen-warning-container" hidden="true" fadeout="true">
     <hbox style="width: 100%;" pack="center"> <!-- Inner hbox needed due to bug 579776. -->
       <vbox id="full-screen-warning-message" align="center">
         <description id="full-screen-domain-text"/>
-        <description class="full-screen-description" value="&fullscreenExitHint.value;"/>
+        <description class="full-screen-description" value="&fullscreenExitHint2.value;"/>
         <vbox id="full-screen-approval-pane" align="center">
-          <description class="full-screen-description" value="&fullscreenApproval.value;"/>
           <hbox>
+#ifdef XP_UNIX
+            <button label="&fullscreenExitButton.label;"
+                    oncommand="FullScreen.setFullscreenAllowed(false);"
+                    class="full-screen-approval-button"/>
+            <button label="&fullscreenAllowButton.label;"
+                    oncommand="FullScreen.setFullscreenAllowed(true);"
+                    class="full-screen-approval-button"/>
+#else
             <button label="&fullscreenAllowButton.label;"
                     oncommand="FullScreen.setFullscreenAllowed(true);"
                     class="full-screen-approval-button"/>
             <button label="&fullscreenExitButton.label;"
                     oncommand="FullScreen.setFullscreenAllowed(false);"
                     class="full-screen-approval-button"/>
+#endif
           </hbox>
           <checkbox id="full-screen-remember-decision"/>
         </vbox>
       </vbox>
     </hbox>
   </hbox>
 
   <vbox id="browser-bottombox" layer="true">
--- a/browser/components/downloads/src/DownloadsCommon.jsm
+++ b/browser/components/downloads/src/DownloadsCommon.jsm
@@ -46,18 +46,22 @@ const Cr = Components.results;
 
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource://gre/modules/Services.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "NetUtil",
                                   "resource://gre/modules/NetUtil.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "PluralForm",
                                   "resource://gre/modules/PluralForm.jsm");
+XPCOMUtils.defineLazyModuleGetter(this, "Downloads",
+                                  "resource://gre/modules/Downloads.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "DownloadUtils",
                                   "resource://gre/modules/DownloadUtils.jsm");
+XPCOMUtils.defineLazyModuleGetter(this, "OS",
+                                  "resource://gre/modules/osfile.jsm")
 XPCOMUtils.defineLazyModuleGetter(this, "PrivateBrowsingUtils",
                                   "resource://gre/modules/PrivateBrowsingUtils.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "RecentWindow",
                                   "resource:///modules/RecentWindow.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "PlacesUtils",
                                   "resource://gre/modules/PlacesUtils.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "DownloadsLogger",
                                   "resource:///modules/DownloadsLogger.jsm");
@@ -577,16 +581,30 @@ XPCOMUtils.defineLazyGetter(DownloadsCom
   let os = Cc["@mozilla.org/xre/app-info;1"].getService(Ci.nsIXULRuntime).OS;
   if (os != "WINNT") {
     return false;
   }
   let sysInfo = Cc["@mozilla.org/system-info;1"].getService(Ci.nsIPropertyBag2);
   return parseFloat(sysInfo.getProperty("version")) >= 6;
 });
 
+/**
+ * Returns true if we should hook the panel to the JavaScript API for downloads
+ * instead of the nsIDownloadManager back-end.  In order for the logic to work
+ * properly, this value never changes during the execution of the application,
+ * even if the underlying preference value has changed.  A restart is required
+ * for the change to take effect.
+ */
+XPCOMUtils.defineLazyGetter(DownloadsCommon, "useJSTransfer", function () {
+  try {
+    return Services.prefs.getBoolPref("browser.download.useJSTransfer");
+  } catch (ex) { }
+  return false;
+});
+
 ////////////////////////////////////////////////////////////////////////////////
 //// DownloadsData
 
 /**
  * Retrieves the list of past and completed downloads from the underlying
  * Download Manager data, and provides asynchronous notifications allowing to
  * build a consistent view of the available data.
  *
@@ -612,48 +630,143 @@ function DownloadsDataCtor(aPrivate) {
   // been removed from the Download Manager data are still present, however the
   // associated objects are replaced with the value "null".  This is required to
   // prevent race conditions when populating the list asynchronously.
   this.dataItems = {};
 
   // Array of view objects that should be notified when the available download
   // data changes.
   this._views = [];
+
+  if (DownloadsCommon.useJSTransfer) {
+    // Maps Download objects to DownloadDataItem objects.
+    this._downloadToDataItemMap = new Map();
+  }
 }
 
 DownloadsDataCtor.prototype = {
   /**
    * Starts receiving events for current downloads.
    *
    * @param aDownloadManagerService
    *        Reference to the service implementing nsIDownloadManager.  We need
    *        this because getService isn't available for us when this method is
    *        called, and we must ensure to register our listeners before the
    *        getService call for the Download Manager returns.
    */
   initializeDataLink: function DD_initializeDataLink(aDownloadManagerService)
   {
     // Start receiving real-time events.
-    aDownloadManagerService.addPrivacyAwareListener(this);
-    Services.obs.addObserver(this, "download-manager-remove-download-guid", false);
+    if (DownloadsCommon.useJSTransfer) {
+      let promiseList = this._isPrivate ? Downloads.getPrivateDownloadList()
+                                        : Downloads.getPublicDownloadList();
+      promiseList.then(list => list.addView(this)).then(null, Cu.reportError);
+    } else {
+      aDownloadManagerService.addPrivacyAwareListener(this);
+      Services.obs.addObserver(this, "download-manager-remove-download-guid",
+                               false);
+    }
   },
 
   /**
    * Stops receiving events for current downloads and cancels any pending read.
    */
   terminateDataLink: function DD_terminateDataLink()
   {
+    if (DownloadsCommon.useJSTransfer) {
+      Cu.reportError("terminateDataLink not applicable with useJSTransfer");
+      return;
+    }
+
     this._terminateDataAccess();
 
     // Stop receiving real-time events.
     Services.obs.removeObserver(this, "download-manager-remove-download-guid");
     Services.downloads.removeListener(this);
   },
 
   //////////////////////////////////////////////////////////////////////////////
+  //// Integration with the asynchronous Downloads back-end
+
+  onDownloadAdded: function (aDownload)
+  {
+    let dataItem = new DownloadsDataItem(aDownload);
+    this._downloadToDataItemMap.set(aDownload, dataItem);
+    this.dataItems[dataItem.downloadGuid] = dataItem;
+
+    for (let view of this._views) {
+      view.onDataItemAdded(dataItem, true);
+    }
+
+    this._updateDataItemState(dataItem);
+  },
+
+  onDownloadChanged: function (aDownload)
+  {
+    let dataItem = this._downloadToDataItemMap.get(aDownload);
+    if (!dataItem) {
+      Cu.reportError("Download doesn't exist.");
+      return;
+    }
+
+    this._updateDataItemState(dataItem);
+  },
+
+  onDownloadRemoved: function (aDownload)
+  {
+    let dataItem = this._downloadToDataItemMap.get(aDownload);
+    if (!dataItem) {
+      Cu.reportError("Download doesn't exist.");
+      return;
+    }
+
+    this._downloadToDataItemMap.remove(aDownload);
+    this.dataItems[dataItem.downloadGuid] = null;
+    for (let view of this._views) {
+      view.onDataItemRemoved(dataItem);
+    }
+  },
+
+  /**
+   * Updates the given data item and sends related notifications.
+   */
+  _updateDataItemState: function (aDataItem)
+  {
+    let wasInProgress = aDataItem.inProgress;
+    let wasDone = aDataItem.done;
+
+    aDataItem.updateFromJSDownload();
+
+    if (wasInProgress && !aDataItem.inProgress) {
+      aDataItem.endTime = Date.now();
+    }
+
+    for (let view of this._views) {
+      try {
+        view.getViewItem(aDataItem).onStateChange({});
+      } catch (ex) {
+        Cu.reportError(ex);
+      }
+    }
+
+    if (!aDataItem.newDownloadNotified) {
+      aDataItem.newDownloadNotified = true;
+      this._notifyDownloadEvent("start");
+    }
+
+    if (!wasDone && aDataItem.done) {
+      this._notifyDownloadEvent("finish");
+    }
+
+    for (let view of this._views) {
+      view.getViewItem(aDataItem).onProgressChange();
+    }
+  },
+
+  //////////////////////////////////////////////////////////////////////////////
   //// Registration of views
 
   /**
    * Adds an object to be notified when the available download data changes.
    * The specified object is initialized with the currently available downloads.
    *
    * @param aView
    *        DownloadsView object to be added.  This reference must be passed to
@@ -1155,29 +1268,92 @@ XPCOMUtils.defineLazyGetter(this, "Downl
 /**
  * Represents a single item in the list of downloads.  This object either wraps
  * an existing nsIDownload from the Download Manager, or provides the same
  * information read directly from the downloads database, with the possibility
  * of querying the nsIDownload lazily, for performance reasons.
  *
  * @param aSource
  *        Object containing the data with which the item should be initialized.
- *        This should implement either nsIDownload or mozIStorageRow.
+ *        This should implement either nsIDownload or mozIStorageRow.  If the
+ *        JavaScript API for downloads is enabled, this is a Download object.
  */
 function DownloadsDataItem(aSource)
 {
-  if (aSource instanceof Ci.nsIDownload) {
+  if (DownloadsCommon.useJSTransfer) {
+    this._initFromJSDownload(aSource);
+  } else if (aSource instanceof Ci.nsIDownload) {
     this._initFromDownload(aSource);
   } else {
     this._initFromDataRow(aSource);
   }
 }
 
 DownloadsDataItem.prototype = {
   /**
+   * The JavaScript API does not need identifiers for Download objects, so they
+   * are generated sequentially for the corresponding DownloadDataItem.
+   */
+  get _autoIncrementId() ++DownloadsDataItem.prototype.__lastId,
+  __lastId: 0,
+
+  /**
+   * Initializes this object from the JavaScript API for downloads.
+   *
+   * The endTime property is initialized to the current date and time.
+   *
+   * @param aDownload
+   *        The Download object with the current state.
+   */
+  _initFromJSDownload: function (aDownload)
+  {
+    this._download = aDownload;
+
+    this.downloadGuid = "id:" + this._autoIncrementId;
+    this.file = aDownload.target.path;
+    this.target = OS.Path.basename(aDownload.target.path);
+    this.uri = aDownload.source.url;
+    this.endTime = Date.now();
+
+    this.updateFromJSDownload();
+  },
+
+  /**
+   * Updates this object from the JavaScript API for downloads.
+   */
+  updateFromJSDownload: function ()
+  {
+    // Collapse state using the correct priority.
+    if (this._download.succeeded) {
+      this.state = nsIDM.DOWNLOAD_FINISHED;
+    } else if (this._download.error &&
+               this._download.error.becauseBlockedByParentalControls) {
+      this.state = nsIDM.DOWNLOAD_BLOCKED_PARENTAL;
+    } else if (this._download.error) {
+      this.state = nsIDM.DOWNLOAD_FAILED;
+    } else if (this._download.canceled && this._download.hasPartialData) {
+      this.state = nsIDM.DOWNLOAD_PAUSED;
+    } else if (this._download.canceled) {
+      this.state = nsIDM.DOWNLOAD_CANCELED;
+    } else if (this._download.stopped) {
+      this.state = nsIDM.DOWNLOAD_NOTSTARTED;
+    } else {
+      this.state = nsIDM.DOWNLOAD_DOWNLOADING;
+    }
+
+    this.referrer = this._download.source.referrer;
+    this.startTime = this._download.startTime;
+    this.currBytes = this._download.currentBytes;
+    this.maxBytes = this._download.totalBytes;
+    this.resumable = this._download.hasPartialData;
+    this.speed = 0;
+    this.percentComplete = this._download.progress;
+  },
+
+  /**
    * Initializes this object from a download object of the Download Manager.
    *
    * The endTime property is initialized to the current date and time.
    *
    * @param aDownload
    *        The nsIDownload with the current state.
    */
   _initFromDownload: function DDI_initFromDownload(aDownload)
@@ -1403,16 +1579,21 @@ DownloadsDataItem.prototype = {
   /**
    * Open the target file for this download.
    *
    * @param aOwnerWindow
    *        The window with which the required action is associated.
    * @throws if the file cannot be opened.
    */
   openLocalFile: function DDI_openLocalFile(aOwnerWindow) {
+    if (DownloadsCommon.useJSTransfer) {
+      this._download.launch().then(null, Cu.reportError);
+      return;
+    }
+
     this.getDownload(function(aDownload) {
       DownloadsCommon.openDownloadedFile(this.localFile,
                                          aDownload.MIMEInfo,
                                          aOwnerWindow);
     }.bind(this));
   },
 
   /**
@@ -1422,16 +1603,25 @@ DownloadsDataItem.prototype = {
     DownloadsCommon.showDownloadedFile(this.localFile);
   },
 
   /**
    * Resumes the download if paused, pauses it if active.
    * @throws if the download is not resumable or if has already done.
    */
   togglePauseResume: function DDI_togglePauseResume() {
+    if (DownloadsCommon.useJSTransfer) {
+      if (this._download.stopped) {
+        this._download.start();
+      } else {
+        this._download.cancel();
+      }
+      return;
+    }
+
     if (!this.inProgress || !this.resumable)
       throw new Error("The given download cannot be paused or resumed");
 
     this.getDownload(function(aDownload) {
       if (this.inProgress) {
         if (this.paused)
           aDownload.resume();
         else
@@ -1440,18 +1630,23 @@ DownloadsDataItem.prototype = {
     }.bind(this));
   },
 
   /**
    * Attempts to retry the download.
    * @throws if we cannot.
    */
   retry: function DDI_retry() {
+    if (DownloadsCommon.useJSTransfer) {
+      this._download.start();
+      return;
+    }
+
     if (!this.canRetry)
-      throw new Error("Cannot rerty this download");
+      throw new Error("Cannot retry this download");
 
     this.getDownload(function(aDownload) {
       aDownload.retry();
     });
   },
 
   /**
    * Support function that deletes the local file for a download. This is
@@ -1468,29 +1663,45 @@ DownloadsDataItem.prototype = {
     } catch (ex) { }
   },
 
   /**
    * Cancels the download.
    * @throws if the download is already done.
    */
   cancel: function() {
+    if (DownloadsCommon.useJSTransfer) {
+      this._download.cancel();
+      this._download.removePartialData().then(null, Cu.reportError);
+      return;
+    }
+
     if (!this.inProgress)
       throw new Error("Cannot cancel this download");
 
     this.getDownload(function (aDownload) {
       aDownload.cancel();
       this._ensureLocalFileRemoved();
     }.bind(this));
   },
 
   /**
    * Remove the download.
    */
   remove: function DDI_remove() {
+    if (DownloadsCommon.useJSTransfer) {
+      let promiseList = this._download.source.isPrivate
+                          ? Downloads.getPrivateDownloadList()
+                          : Downloads.getPublicDownloadList();
+      promiseList.then(list => list.remove(this._download))
+                 .then(() => this._download.finalize(true))
+                 .then(null, Cu.reportError);
+      return;
+    }
+
     this.getDownload(function (aDownload) {
       if (this.inProgress) {
         aDownload.cancel();
         this._ensureLocalFileRemoved();
       }
       aDownload.remove();
     }.bind(this));
   }
--- a/browser/components/downloads/src/DownloadsStartup.js
+++ b/browser/components/downloads/src/DownloadsStartup.js
@@ -81,43 +81,45 @@ DownloadsStartup.prototype = {
 
   //////////////////////////////////////////////////////////////////////////////
   //// nsIObserver
 
   observe: function DS_observe(aSubject, aTopic, aData)
   {
     switch (aTopic) {
       case "profile-after-change":
-        kObservedTopics.forEach(
-          function (topic) Services.obs.addObserver(this, topic, true),
-          this);
-
         // Override Toolkit's nsIDownloadManagerUI implementation with our own.
         // This must be done at application startup and not in the manifest to
         // ensure that our implementation overrides the original one.
         Components.manager.QueryInterface(Ci.nsIComponentRegistrar)
                           .registerFactory(kDownloadsUICid, "",
                                            kDownloadsUIContractId, null);
 
         // If the integration preference is enabled, override Toolkit's
         // nsITransfer implementation with the one from the JavaScript API for
         // downloads.  This should be used only by developers while testing new
         // code that uses the JavaScript API, and will eventually be removed
         // when nsIDownloadManager will not be available anymore (bug 851471).
         let useJSTransfer = false;
         try {
+          // For performance reasons, we don't want to load the DownloadsCommon
+          // module during startup, so we read the preference value directly.
           useJSTransfer =
             Services.prefs.getBoolPref("browser.download.useJSTransfer");
-        } catch (ex) {
-          // This is a hidden preference that does not exist by default.
-        }
+        } catch (ex) { }
         if (useJSTransfer) {
           Components.manager.QueryInterface(Ci.nsIComponentRegistrar)
                             .registerFactory(kTransferCid, "",
                                              kTransferContractId, null);
+        } else {
+          // The other notifications are handled internally by the JavaScript
+          // API for downloads, no need to observe when that API is enabled.
+          for (let topic of kObservedTopics) {
+            Services.obs.addObserver(this, topic, true);
+          }
         }
         break;
 
       case "sessionstore-windows-restored":
       case "sessionstore-browser-state-restored":
         // Unless there is no saved session, there is a chance that we are
         // starting up after a restart or a crash.  We should check the disk
         // database to see if there are completed downloads to recover and show
--- a/browser/components/sessionstore/src/SessionStore.jsm
+++ b/browser/components/sessionstore/src/SessionStore.jsm
@@ -107,18 +107,16 @@ let gDocShellCapabilities = (function ()
       let keys = Object.keys(docShell);
       caps = keys.filter(k => k.startsWith("allow")).map(k => k.slice(5));
     }
 
     return caps;
   };
 })();
 
-XPCOMUtils.defineLazyModuleGetter(this, "NetUtil",
-  "resource://gre/modules/NetUtil.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "ScratchpadManager",
   "resource:///modules/devtools/scratchpad-manager.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "DocumentUtils",
   "resource:///modules/sessionstore/DocumentUtils.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "SessionStorage",
   "resource:///modules/sessionstore/SessionStorage.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "_SessionFile",
   "resource:///modules/sessionstore/_SessionFile.jsm");
@@ -344,26 +342,16 @@ let SessionStoreInternal = {
 
   // Whether session has been initialized
   _sessionInitialized: false,
 
   // True if session store is disabled by multi-process browsing.
   // See bug 516755.
   _disabledForMultiProcess: false,
 
-  // The original "sessionstore.resume_session_once" preference value before it
-  // was modified by saveState.  saveState will set the
-  // "sessionstore.resume_session_once" to true when the
-  // the "sessionstore.resume_from_crash" preference is false (crash recovery
-  // is disabled) so that pinned tabs will be restored in the case of a
-  // crash.  This variable is used to restore the original value so the
-  // previous session is not always restored when
-  // "sessionstore.resume_from_crash" is true.
-  _resume_session_once_on_shutdown: null,
-
   /**
    * A promise fulfilled once initialization is complete.
    */
   get promiseInitialized() {
     return this._deferredInitialized.promise;
   },
 
   /* ........ Public Getters .............. */
@@ -1052,25 +1040,16 @@ let SessionStoreInternal = {
       // The browser:purge-session-history notification fires after the
       // quit-application notification so unregister the
       // browser:purge-session-history notification to prevent clearing
       // session data on disk on a restart.  It is also unnecessary to
       // perform any other sanitization processing on a restart as the
       // browser is about to exit anyway.
       Services.obs.removeObserver(this, "browser:purge-session-history");
     }
-    else if (this._resume_session_once_on_shutdown != null) {
-      // if the sessionstore.resume_session_once preference was changed by
-      // saveState because crash recovery is disabled then restore the
-      // preference back to the value it was prior to that.  This will prevent
-      // SessionStore from always restoring the session when crash recovery is
-      // disabled.
-      this._prefBranch.setBoolPref("sessionstore.resume_session_once",
-                                   this._resume_session_once_on_shutdown);
-    }
 
     if (aData != "restart") {
       // Throw away the previous session on shutdown
       this._lastSessionState = null;
     }
 
     this._loadState = STATE_QUITTING; // just to be sure
     this._uninit();
@@ -1209,22 +1188,16 @@ let SessionStoreInternal = {
         if (this._saveTimer) {
           this._saveTimer.cancel();
           this._saveTimer = null;
         }
         this.saveStateDelayed(null, -1);
         break;
       case "sessionstore.resume_from_crash":
         this._resume_from_crash = this._prefBranch.getBoolPref("sessionstore.resume_from_crash");
-        // restore original resume_session_once preference if set in saveState
-        if (this._resume_session_once_on_shutdown != null) {
-          this._prefBranch.setBoolPref("sessionstore.resume_session_once",
-                                       this._resume_session_once_on_shutdown);
-          this._resume_session_once_on_shutdown = null;
-        }
         // either create the file with crash recovery information or remove it
         // (when _loadState is not STATE_RUNNING, that file is used for session resuming instead)
         if (!this._resume_from_crash)
           _SessionFile.wipe();
         this.saveState(true);
         break;
     }
   },
@@ -3836,29 +3809,16 @@ let SessionStoreInternal = {
       }
       else {
         // We only need to go until we hit !needsRestore since we're going in reverse
         break;
       }
     }
 #endif
 
-    if (pinnedOnly) {
-      // Save original resume_session_once preference for when quiting browser,
-      // otherwise session will be restored next time browser starts and we
-      // only want it to be restored in the case of a crash.
-      if (this._resume_session_once_on_shutdown == null) {
-        this._resume_session_once_on_shutdown =
-          this._prefBranch.getBoolPref("sessionstore.resume_session_once");
-        this._prefBranch.setBoolPref("sessionstore.resume_session_once", true);
-        // flush the preference file so preference will be saved in case of a crash
-        Services.prefs.savePrefFile(null);
-      }
-    }
-
     // Persist the last session if we deferred restoring it
     if (this._lastSessionState)
       oState.lastSessionState = this._lastSessionState;
 
     TelemetryStopwatch.finish("FX_SESSION_RESTORE_COLLECT_DATA_MS");
     TelemetryStopwatch.finish("FX_SESSION_RESTORE_COLLECT_DATA_LONGEST_OP_MS");
 
     this._saveStateObject(oState);
--- a/browser/devtools/commandline/BuiltinCommands.jsm
+++ b/browser/devtools/commandline/BuiltinCommands.jsm
@@ -14,24 +14,22 @@ this.EXPORTED_SYMBOLS = [ "CmdAddonFlags
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource://gre/modules/Services.jsm");
 let promise = Cu.import("resource://gre/modules/commonjs/sdk/core/promise.js").Promise;
 Cu.import("resource://gre/modules/osfile.jsm");
 
 Cu.import("resource://gre/modules/devtools/gcli.jsm");
 Cu.import("resource:///modules/devtools/shared/event-emitter.js");
 
-var require = Cu.import("resource://gre/modules/devtools/Loader.jsm", {}).devtools.require;
-let Telemetry = require("devtools/shared/telemetry");
+let devtools = Cu.import("resource://gre/modules/devtools/Loader.jsm", {}).devtools;
+let Telemetry = devtools.require("devtools/shared/telemetry");
 let telemetry = new Telemetry();
 
 XPCOMUtils.defineLazyModuleGetter(this, "gDevTools",
                                   "resource:///modules/devtools/gDevTools.jsm");
-XPCOMUtils.defineLazyModuleGetter(this, "devtools",
-                                  "resource://gre/modules/devtools/Loader.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "AppCacheUtils",
                                   "resource:///modules/devtools/AppCacheUtils.jsm");
 
 /* CmdAddon ---------------------------------------------------------------- */
 
 (function(module) {
   XPCOMUtils.defineLazyModuleGetter(this, "AddonManager",
                                     "resource://gre/modules/AddonManager.jsm");
@@ -794,18 +792,23 @@ XPCOMUtils.defineLazyModuleGetter(this, 
       return gcli.lookupFormat("cmdStatus", [ commands.length, args.directory ]);
     }
   });
 }(this));
 
 /* CmdConsole -------------------------------------------------------------- */
 
 (function(module) {
-  XPCOMUtils.defineLazyModuleGetter(this, "HUDService",
-                                    "resource:///modules/HUDService.jsm");
+  Object.defineProperty(this, "HUDService", {
+    get: function() {
+      return devtools.require("devtools/webconsole/hudservice");
+    },
+    configurable: true,
+    enumerable: true
+  });
 
   /**
    * 'console' command
    */
   gcli.addCommand({
     name: "console",
     description: gcli.lookup("consoleDesc"),
     manual: gcli.lookup("consoleManual")
--- a/browser/devtools/commandline/test/browser_cmd_calllog.js
+++ b/browser/devtools/commandline/test/browser_cmd_calllog.js
@@ -1,15 +1,13 @@
 /* Any copyright is dedicated to the Public Domain.
 * http://creativecommons.org/publicdomain/zero/1.0/ */
 
 // Tests that the calllog commands works as they should
 
-let HUDService = (Cu.import("resource:///modules/HUDService.jsm", {})).HUDService;
-
 const TEST_URI = "data:text/html;charset=utf-8,gcli-calllog";
 
 let tests = {};
 
 function test() {
   helpers.addTabWithToolbar(TEST_URI, function(options) {
     return helpers.runTests(options, tests);
   }).then(finish);
@@ -50,17 +48,17 @@ tests.testCallLogStatus = function(optio
 tests.testCallLogExec = function(options) {
   var deferred = promise.defer();
 
   var onWebConsoleOpen = function(subject) {
     Services.obs.removeObserver(onWebConsoleOpen, "web-console-created");
 
     subject.QueryInterface(Ci.nsISupportsString);
     let hud = HUDService.getHudReferenceById(subject.data);
-    ok(hud.hudId in HUDService.hudReferences, "console open");
+    ok(hud, "console open");
 
     helpers.audit(options, [
       {
         setup: "calllog stop",
         exec: {
           output: /Stopped call logging/,
         }
       },
--- a/browser/devtools/commandline/test/browser_cmd_calllog_chrome.js
+++ b/browser/devtools/commandline/test/browser_cmd_calllog_chrome.js
@@ -1,15 +1,13 @@
 /* Any copyright is dedicated to the Public Domain.
 * http://creativecommons.org/publicdomain/zero/1.0/ */
 
 // Tests that the calllog commands works as they should
 
-let HUDService = (Cu.import("resource:///modules/HUDService.jsm", {})).HUDService;
-
 const TEST_URI = "data:text/html;charset=utf-8,cmd-calllog-chrome";
 
 let tests = {};
 
 function test() {
   helpers.addTabWithToolbar(TEST_URI, function(options) {
     return helpers.runTests(options, tests);
   }).then(finish);
@@ -51,17 +49,17 @@ tests.testCallLogStatus = function(optio
 tests.testCallLogExec = function(options) {
   let deferred = promise.defer();
 
   function onWebConsoleOpen(subject) {
     Services.obs.removeObserver(onWebConsoleOpen, "web-console-created");
 
     subject.QueryInterface(Ci.nsISupportsString);
     let hud = HUDService.getHudReferenceById(subject.data);
-    ok(hud.hudId in HUDService.hudReferences, "console open");
+    ok(hud, "console open");
 
     helpers.audit(options, [
       {
         setup: "calllog chromestop",
         exec: {
           output: /Stopped call logging/,
         }
       },
--- a/browser/devtools/commandline/test/browser_cmd_commands.js
+++ b/browser/devtools/commandline/test/browser_cmd_commands.js
@@ -1,15 +1,13 @@
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/ */
 
 // Test various GCLI commands
 
-let HUDService = (Cu.import("resource:///modules/HUDService.jsm", {})).HUDService;
-
 const TEST_URI = "data:text/html;charset=utf-8,gcli-commands";
 
 let tests = {};
 
 function test() {
   helpers.addTabWithToolbar(TEST_URI, function(options) {
     return helpers.runTests(options, tests);
   }).then(finish);
@@ -19,51 +17,56 @@ tests.testConsole = function(options) {
   let deferred = promise.defer();
   let hud = null;
 
   let onWebConsoleOpen = function(subject) {
     Services.obs.removeObserver(onWebConsoleOpen, "web-console-created");
 
     subject.QueryInterface(Ci.nsISupportsString);
     hud = HUDService.getHudReferenceById(subject.data);
-    ok(hud.hudId in HUDService.hudReferences, "console open");
+    ok(hud, "console open");
 
     hud.jsterm.execute("pprint(window)", onExecute);
   }
   Services.obs.addObserver(onWebConsoleOpen, "web-console-created", false);
 
-  let onExecute = function() {
+  function onExecute () {
     let labels = hud.outputNode.querySelectorAll(".webconsole-msg-output");
     ok(labels.length > 0, "output for pprint(window)");
 
+    hud.jsterm.once("messages-cleared", onClear);
+
     helpers.audit(options, [
       {
         setup: "console clear",
         exec: {
           output: ""
         },
-        post: function() {
-          let labels = hud.outputNode.querySelectorAll(".webconsole-msg-output");
-          // Bug 845827 - The GCLI "console clear" command doesn't always work
-          // is(labels.length, 0, "no output in console");
-        }
-      },
+      }
+    ]);
+  }
+
+  function onClear() {
+    let labels = hud.outputNode.querySelectorAll(".webconsole-msg-output");
+    is(labels.length, 0, "no output in console");
+
+    helpers.audit(options, [
       {
         setup: "console close",
         exec: {
           output: ""
         },
         post: function() {
-          ok(!(hud.hudId in HUDService.hudReferences), "console closed");
+          ok(!HUDService.getHudReferenceById(hud.hudId), "console closed");
         }
       }
     ]).then(function() {
       deferred.resolve();
     });
-  };
+  }
 
   helpers.audit(options, [
     {
       setup: "console open",
       exec: { }
     }
   ]);
 
--- a/browser/devtools/debugger/CmdDebugger.jsm
+++ b/browser/devtools/debugger/CmdDebugger.jsm
@@ -501,21 +501,22 @@ gcli.addCommand({
       }
 
       // Send the black box request to each source we are black boxing. As we
       // get responses, accumulate the results in `blackBoxed`.
 
       const blackBoxed = [];
 
       for (let source of toBlackBox) {
+        let { url } = source;
         activeThread.source(source)[cmd.clientMethod](function ({ error }) {
           if (error) {
-            blackBoxed.push(lookup("ErrorDesc") + " " + source.url);
+            blackBoxed.push(lookup("ErrorDesc") + " " + url);
           } else {
-            blackBoxed.push(source.url);
+            blackBoxed.push(url);
           }
 
           if (toBlackBox.length === blackBoxed.length) {
             displayResults();
           }
         });
       }
 
--- a/browser/devtools/debugger/debugger-controller.js
+++ b/browser/devtools/debugger/debugger-controller.js
@@ -24,18 +24,27 @@ Cu.import("resource:///modules/devtools/
 Cu.import("resource:///modules/devtools/SideMenuWidget.jsm");
 Cu.import("resource:///modules/devtools/VariablesView.jsm");
 Cu.import("resource:///modules/devtools/VariablesViewController.jsm");
 Cu.import("resource:///modules/devtools/ViewHelpers.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "Parser",
   "resource:///modules/devtools/Parser.jsm");
 
-XPCOMUtils.defineLazyModuleGetter(this, "NetworkHelper",
-  "resource://gre/modules/devtools/NetworkHelper.jsm");
+XPCOMUtils.defineLazyModuleGetter(this, "devtools",
+  "resource://gre/modules/devtools/Loader.jsm");
+
+Object.defineProperty(this, "NetworkHelper", {
+  get: function() {
+    return devtools.require("devtools/toolkit/webconsole/network-helper");
+  },
+  configurable: true,
+  enumerable: true
+});
+
 
 /**
  * Object defining the debugger controller components.
  */
 let DebuggerController = {
   /**
    * Initializes the debugger controller.
    */
@@ -433,16 +442,17 @@ StackFrames.prototype = {
   autoScopeExpand: false,
   currentFrame: null,
   syncedWatchExpressions: null,
   currentWatchExpressions: null,
   currentBreakpointLocation: null,
   currentEvaluation: null,
   currentException: null,
   currentReturnedValue: null,
+  _dontSwitchSources: false,
 
   /**
    * Connect to the current thread client.
    */
   connect: function() {
     dumpn("StackFrames is connecting...");
     this.activeThread.addListener("paused", this._onPaused);
     this.activeThread.addListener("resumed", this._onResumed);
@@ -589,36 +599,50 @@ StackFrames.prototype = {
         return;
       }
     }
 
 
     // Make sure the debugger view panes are visible.
     DebuggerView.showInstrumentsPane();
 
+    this._refillFrames();
+  },
+
+  /**
+   * Fill the StackFrames view with the frames we have in the cache, compressing
+   * frames which have black boxed sources into single frames.
+   */
+  _refillFrames: function() {
     // Make sure all the previous stackframes are removed before re-adding them.
     DebuggerView.StackFrames.empty();
 
     let previousBlackBoxed = null;
     for (let frame of this.activeThread.cachedFrames) {
-      let { depth, where: { url, line }, isBlackBoxed } = frame;
+      let { depth, where: { url, line }, source } = frame;
+
+      let isBlackBoxed = source
+        ? this.activeThread.source(source).isBlackBoxed
+        : false;
       let frameLocation = NetworkHelper.convertToUnicode(unescape(url));
       let frameTitle = StackFrameUtils.getFrameTitle(frame);
 
       if (isBlackBoxed) {
         if (previousBlackBoxed == url) {
           continue;
         }
         previousBlackBoxed = url;
       } else {
         previousBlackBoxed = null;
       }
 
-      DebuggerView.StackFrames.addFrame(frameTitle, frameLocation, line, depth, isBlackBoxed);
+      DebuggerView.StackFrames.addFrame(
+        frameTitle, frameLocation, line, depth, isBlackBoxed);
     }
+
     if (this.currentFrame == null) {
       DebuggerView.StackFrames.selectedDepth = 0;
     }
     if (this.activeThread.moreFrames) {
       DebuggerView.StackFrames.dirty = true;
     }
   },
 
@@ -639,20 +663,19 @@ StackFrames.prototype = {
     window.setTimeout(this._afterFramesCleared, FRAME_STEP_CLEAR_DELAY);
   },
 
   /**
    * Handler for the debugger's blackboxchange notification.
    */
   _onBlackBoxChange: function() {
     if (this.activeThread.state == "paused") {
-      // We have to clear out the existing frames and refetch them to get their
-      // updated black boxed status.
-      this.activeThread._clearFrames();
-      this.activeThread.fillFrames(CALL_STACK_PAGE_SIZE);
+      this._dontSwitchSources = true;
+      this.currentFrame = null;
+      this._refillFrames();
     }
   },
 
   /**
    * Called soon after the thread client's framescleared notification.
    */
   _afterFramesCleared: function() {
     // Ignore useless notifications.
@@ -667,32 +690,37 @@ StackFrames.prototype = {
   },
 
   /**
    * Marks the stack frame at the specified depth as selected and updates the
    * properties view with the stack frame's data.
    *
    * @param number aDepth
    *        The depth of the frame in the stack.
+   * @param boolean aDontSwitchSources
+   *        Flag on whether or not we want to switch the selected source.
    */
-  selectFrame: function(aDepth) {
+  selectFrame: function(aDepth, aDontSwitchSources) {
     // Make sure the frame at the specified depth exists first.
     let frame = this.activeThread.cachedFrames[this.currentFrame = aDepth];
     if (!frame) {
       return;
     }
 
     // Check if the frame does not represent the evaluation of debuggee code.
     let { environment, where: { url, line } } = frame;
     if (!environment) {
       return;
     }
 
+    let noSwitch = this._dontSwitchSources;
+    this._dontSwitchSources = false;
+
     // Move the editor's caret to the proper url and line.
-    DebuggerView.updateEditor(url, line);
+    DebuggerView.updateEditor(url, line, { noSwitch: noSwitch });
     // Highlight the breakpoint at the specified url and line if it exists.
     DebuggerView.Sources.highlightBreakpoint(url, line);
     // Don't display the watch expressions textbox inputs in the pane.
     DebuggerView.WatchExpressions.toggleContents(false);
     // Start recording any added variables or properties in any scope.
     DebuggerView.Variables.createHierarchy();
     // Clear existing scopes and create each one dynamically.
     DebuggerView.Variables.empty();
--- a/browser/devtools/debugger/debugger.xul
+++ b/browser/devtools/debugger/debugger.xul
@@ -188,28 +188,44 @@
          keycode="VK_DOWN"
          modifiers="accel alt"
          command="nextSourceCommand"/>
     <key id="prevSourceKey"
          keycode="VK_UP"
          modifiers="accel alt"
          command="prevSourceCommand"/>
     <key id="resumeKey"
-         keycode="&debuggerUI.stepping.resume;"
+         keycode="&debuggerUI.stepping.resume1;"
+         command="resumeCommand"/>
+    <key id="resumeKey2"
+         keycode="&debuggerUI.stepping.resume2;"
+         modifiers="accel"
          command="resumeCommand"/>
     <key id="stepOverKey"
-         keycode="&debuggerUI.stepping.stepOver;"
+         keycode="&debuggerUI.stepping.stepOver1;"
+         command="stepOverCommand"/>
+    <key id="stepOverKey2"
+         keycode="&debuggerUI.stepping.stepOver2;"
+         modifiers="accel"
          command="stepOverCommand"/>
     <key id="stepInKey"
-         keycode="&debuggerUI.stepping.stepIn;"
+         keycode="&debuggerUI.stepping.stepIn1;"
+         command="stepInCommand"/>
+    <key id="stepInKey2"
+         keycode="&debuggerUI.stepping.stepIn2;"
+         modifiers="accel"
          command="stepInCommand"/>
     <key id="stepOutKey"
-         keycode="&debuggerUI.stepping.stepOut;"
+         keycode="&debuggerUI.stepping.stepOut1;"
          modifiers="shift"
          command="stepOutCommand"/>
+    <key id="stepOutKey2"
+         keycode="&debuggerUI.stepping.stepOut2;"
+         modifiers="accel shift"
+         command="stepOutCommand"/>
     <key id="fileSearchKey"
          key="&debuggerUI.searchFile.key;"
          modifiers="accel"
          command="fileSearchCommand"/>
     <key id="fileSearchKey"
          key="&debuggerUI.searchFile.altkey;"
          modifiers="accel"
          command="fileSearchCommand"/>
--- a/browser/devtools/debugger/test/Makefile.in
+++ b/browser/devtools/debugger/test/Makefile.in
@@ -12,16 +12,18 @@ include $(DEPTH)/config/autoconf.mk
 
 MOCHITEST_BROWSER_TESTS = \
 	browser_dbg_aaa_run_first_leaktest.js \
 	browser_dbg_blackboxing-01.js \
 	browser_dbg_blackboxing-02.js \
 	browser_dbg_blackboxing-03.js \
 	browser_dbg_blackboxing-04.js \
 	browser_dbg_blackboxing-05.js \
+	browser_dbg_blackboxing-06.js \
+	browser_dbg_blackboxing-07.js \
 	browser_dbg_clean-exit.js \
 	browser_dbg_cmd.js \
 	browser_dbg_cmd_blackbox.js \
 	browser_dbg_cmd_break.js \
 	browser_dbg_debuggerstatement.js \
 	browser_dbg_listtabs-01.js \
 	browser_dbg_listtabs-02.js \
 	browser_dbg_tabactor-01.js \
--- a/browser/devtools/debugger/test/browser_dbg_blackboxing-03.js
+++ b/browser/devtools/debugger/test/browser_dbg_blackboxing-03.js
@@ -52,27 +52,25 @@ function testBlackBoxStack() {
 }
 
 function testBlackBoxSource() {
   const checkbox = getBlackBoxCheckbox(BLACKBOXME_URL);
   ok(checkbox, "Should get the checkbox for black boxing the source");
 
   const { activeThread } = gDebugger.DebuggerController;
   activeThread.addOneTimeListener("blackboxchange", function (event, sourceClient) {
-    activeThread.addOneTimeListener("framesadded", function () {
-      ok(sourceClient.isBlackBoxed, "The source should be black boxed now");
+    ok(sourceClient.isBlackBoxed, "The source should be black boxed now");
 
-      const frames = gDebugger.DebuggerView.StackFrames.widget._list;
-      is(frames.querySelectorAll(".dbg-stackframe").length, 3,
-         "Should only get 3 frames");
-      is(frames.querySelectorAll(".dbg-stackframe-black-boxed").length, 1,
-         "And one of them is the combined black boxed frames");
+    const frames = gDebugger.DebuggerView.StackFrames.widget._list;
+    is(frames.querySelectorAll(".dbg-stackframe").length, 3,
+       "Should only get 3 frames");
+    is(frames.querySelectorAll(".dbg-stackframe-black-boxed").length, 1,
+       "And one of them is the combined black boxed frames");
 
-      closeDebuggerAndFinish();
-    });
+    closeDebuggerAndFinish();
   });
 
   checkbox.click();
 }
 
 function getBlackBoxCheckbox(url) {
   return gDebugger.document.querySelector(
     ".side-menu-widget-item[tooltiptext=\""
--- a/browser/devtools/debugger/test/browser_dbg_blackboxing-05.js
+++ b/browser/devtools/debugger/test/browser_dbg_blackboxing-05.js
@@ -36,17 +36,17 @@ function testSourceEditorShown() {
   is(deck.selectedIndex, "0",
      "The first item in the deck should be selected (the source editor)");
   blackBoxSource();
 }
 
 function blackBoxSource() {
   const { activeThread } = gDebugger.DebuggerController;
   activeThread.addOneTimeListener("blackboxchange", testBlackBoxMessageShown);
-  getBlackBoxCheckbox().click();
+  getAnyBlackBoxCheckbox().click();
 }
 
 function testBlackBoxMessageShown() {
   const deck = gDebugger.document.getElementById("editor-deck");
   is(deck.selectedIndex, "1",
      "The second item in the deck should be selected (the black box message)");
   clickStopBlackBoxingButton();
 }
@@ -60,17 +60,17 @@ function clickStopBlackBoxingButton() {
 
 function testSourceEditorShownAgain() {
   const deck = gDebugger.document.getElementById("editor-deck");
   is(deck.selectedIndex, "0",
      "The first item in the deck should be selected again (the source editor)");
   closeDebuggerAndFinish();
 }
 
-function getBlackBoxCheckbox() {
+function getAnyBlackBoxCheckbox() {
   return gDebugger.document.querySelector(
     ".side-menu-widget-item .side-menu-widget-item-checkbox");
 }
 
 function once(target, event, callback) {
   target.addEventListener(event, function _listener(...args) {
     target.removeEventListener(event, _listener, false);
     callback.apply(null, args);
new file mode 100644
--- /dev/null
+++ b/browser/devtools/debugger/test/browser_dbg_blackboxing-06.js
@@ -0,0 +1,70 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+/**
+ * Test that clicking the black box checkbox doesn't select that source.
+ */
+
+const TAB_URL = EXAMPLE_URL + "browser_dbg_blackboxing.html";
+
+var gPane = null;
+var gTab = null;
+var gDebuggee = null;
+var gDebugger = null;
+
+function test()
+{
+  let scriptShown = false;
+  let framesAdded = false;
+  let resumed = false;
+  let testStarted = false;
+
+  debug_tab_pane(TAB_URL, function(aTab, aDebuggee, aPane) {
+    resumed = true;
+    gTab = aTab;
+    gDebuggee = aDebuggee;
+    gPane = aPane;
+    gDebugger = gPane.panelWin;
+
+    once(gDebugger, "Debugger:SourceShown", testBlackBox);
+  });
+}
+
+function testBlackBox() {
+  const sources = gDebugger.DebuggerView.Sources;
+
+  const selectedUrl = sources.selectedItem.attachment.source.url;
+  const checkbox = getDifferentBlackBoxCheckbox(selectedUrl);
+  ok(checkbox, "We should be able to grab a checkbox");
+
+  const { activeThread } = gDebugger.DebuggerController;
+  activeThread.addOneTimeListener("blackboxchange", function () {
+    is(selectedUrl,
+       sources.selectedItem.attachment.source.url,
+       "The same source should be selected");
+    closeDebuggerAndFinish();
+  });
+
+  checkbox.click();
+}
+
+function getDifferentBlackBoxCheckbox(url) {
+  return gDebugger.document.querySelector(
+    ".side-menu-widget-item:not([tooltiptext=\""
+      + url + "\"]) .side-menu-widget-item-checkbox");
+}
+
+function once(target, event, callback) {
+  target.addEventListener(event, function _listener(...args) {
+    target.removeEventListener(event, _listener, false);
+    callback.apply(null, args);
+  }, false);
+}
+
+registerCleanupFunction(function() {
+  removeTab(gTab);
+  gPane = null;
+  gTab = null;
+  gDebuggee = null;
+  gDebugger = null;
+});
new file mode 100644
--- /dev/null
+++ b/browser/devtools/debugger/test/browser_dbg_blackboxing-07.js
@@ -0,0 +1,86 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+/**
+ * Test that clicking the black box checkbox when paused doesn't re-select the
+ * currently paused frame's source.
+ */
+
+const TAB_URL = EXAMPLE_URL + "browser_dbg_blackboxing.html";
+
+var gPane = null;
+var gTab = null;
+var gDebuggee = null;
+var gDebugger = null;
+
+function test()
+{
+  let scriptShown = false;
+  let framesAdded = false;
+  let resumed = false;
+  let testStarted = false;
+
+  debug_tab_pane(TAB_URL, function(aTab, aDebuggee, aPane) {
+    resumed = true;
+    gTab = aTab;
+    gDebuggee = aDebuggee;
+    gPane = aPane;
+    gDebugger = gPane.panelWin;
+
+    once(gDebugger, "Debugger:SourceShown", runTest);
+  });
+}
+
+function runTest() {
+  const { activeThread } = gDebugger.DebuggerController;
+  activeThread.addOneTimeListener("paused", function () {
+    const sources = gDebugger.DebuggerView.Sources;
+    const selectedUrl = sources.selectedItem.attachment.source.url;
+
+    once(gDebugger, "Debugger:SourceShown", function () {
+      const newSelectedUrl = sources.selectedItem.attachment.source.url;
+      isnot(selectedUrl, newSelectedUrl,
+            "Should not have the same url selected");
+
+      activeThread.addOneTimeListener("blackboxchange", function () {
+        isnot(sources.selectedItem.attachment.source.url,
+              selectedUrl,
+              "The selected source did not change");
+        closeDebuggerAndFinish();
+      });
+
+      getBlackBoxCheckbox(newSelectedUrl).click();
+    });
+
+    getDifferentSource(selectedUrl).click();
+  });
+
+  gDebuggee.runTest();
+}
+
+function getDifferentSource(url) {
+  return gDebugger.document.querySelector(
+    ".side-menu-widget-item:not([tooltiptext=\""
+      + url + "\"])");
+}
+
+function getBlackBoxCheckbox(url) {
+  return gDebugger.document.querySelector(
+    ".side-menu-widget-item[tooltiptext=\""
+      + url + "\"] .side-menu-widget-item-checkbox");
+}
+
+function once(target, event, callback) {
+  target.addEventListener(event, function _listener(...args) {
+    target.removeEventListener(event, _listener, false);
+    callback.apply(null, args);
+  }, false);
+}
+
+registerCleanupFunction(function() {
+  removeTab(gTab);
+  gPane = null;
+  gTab = null;
+  gDebuggee = null;
+  gDebugger = null;
+});
--- a/browser/devtools/debugger/test/browser_dbg_cmd_blackbox.js
+++ b/browser/devtools/debugger/test/browser_dbg_cmd_blackbox.js
@@ -15,31 +15,37 @@ let gcli = Cu.import("resource://gre/mod
 let gTarget;
 let gPanel;
 let gOptions;
 let gDebugger;
 let gClient;
 let gThreadClient;
 let gTab;
 
-function cmd(typed, expectedNumEvents=1) {
+function cmd(typed, expectedNumEvents=1, output=null) {
   const deferred = promise.defer();
 
   let timesFired = 0;
   gThreadClient.addListener("blackboxchange", function _onBlackBoxChange() {
     if (++timesFired === expectedNumEvents) {
       gThreadClient.removeListener("blackboxchange", _onBlackBoxChange);
       deferred.resolve();
     }
   });
 
-  helpers.audit(gOptions, [{
+  let audit = {
     setup: typed,
     exec: {}
-  }]);
+  };
+
+  if (output) {
+    audit.output = output;
+  }
+
+  helpers.audit(gOptions, [audit]);
 
   return deferred.promise;
 }
 
 function test() {
   helpers.addTabWithToolbar(TEST_URL, function(options) {
     gOptions = options;
     gTarget = options.target;
@@ -88,17 +94,18 @@ function testUnBlackBoxSource() {
     .then(function () {
       const checkbox = getBlackBoxCheckbox(BLACKBOXME_URL);
       ok(checkbox.checked,
          "Should be able to stop black boxing a specific source");
     });
 }
 
 function testBlackBoxGlob() {
-  return cmd("dbg blackbox --glob *blackboxing_t*.js", 2)
+  return cmd("dbg blackbox --glob *blackboxing_t*.js", 2,
+             [/blackboxing_three\.js/g, /blackboxing_two\.js/g])
     .then(function () {
       ok(getBlackBoxCheckbox(BLACKBOXME_URL).checked,
          "blackboxme should not be black boxed because it doesn't match the glob");
       ok(getBlackBoxCheckbox(BLACKBOXONE_URL).checked,
          "blackbox_one should not be black boxed because it doesn't match the glob");
 
       ok(!getBlackBoxCheckbox(BLACKBOXTWO_URL).checked,
          "blackbox_two should be black boxed because it matches the glob");
--- a/browser/devtools/framework/gDevTools.jsm
+++ b/browser/devtools/framework/gDevTools.jsm
@@ -14,16 +14,17 @@ Cu.import("resource:///modules/devtools/
 let promise = Cu.import("resource://gre/modules/commonjs/sdk/core/promise.js").Promise;
 Cu.import("resource://gre/modules/devtools/Loader.jsm");
 
 var ProfilerController = devtools.require("devtools/profiler/controller");
 
 const FORBIDDEN_IDS = new Set(["toolbox", ""]);
 const MAX_ORDINAL = 99;
 
+
 /**
  * DevTools is a class that represents a set of developer tools, it holds a
  * set of tools and keeps track of open toolboxes in the browser.
  */
 this.DevTools = function DevTools() {
   this._tools = new Map();     // Map<toolId, tool>
   this._toolboxes = new Map(); // Map<target, toolbox>
 
@@ -340,25 +341,34 @@ let gDevToolsBrowser = {
    * - if the toolbox is open, and the targetted tool is selected,
    *   and the host is NOT a window, we close the toolbox
    * - if the toolbox is open, and the targetted tool is selected,
    *   and the host is a window, we raise the toolbox window
    */
   selectToolCommand: function(gBrowser, toolId) {
     let target = devtools.TargetFactory.forTab(gBrowser.selectedTab);
     let toolbox = gDevTools.getToolbox(target);
+    let tools = gDevTools.getToolDefinitionMap();
+    let toolDefinition = tools.get(toolId);
 
     if (toolbox && toolbox.currentToolId == toolId) {
-      if (toolbox.hostType == devtools.Toolbox.HostType.WINDOW) {
+      toolbox.fireCustomKey(toolId);
+
+      if (toolDefinition.preventClosingOnKey || toolbox.hostType == devtools.Toolbox.HostType.WINDOW) {
         toolbox.raise();
       } else {
         toolbox.destroy();
       }
     } else {
-      gDevTools.showToolbox(target, toolId);
+      gDevTools.showToolbox(target, toolId).then(() => {
+        let target = devtools.TargetFactory.forTab(gBrowser.selectedTab);
+        let toolbox = gDevTools.getToolbox(target);
+
+        toolbox.fireCustomKey(toolId);
+      });
     }
   },
 
   /**
    * Open a tab to allow connects to a remote browser
    */
   openConnectScreen: function(gBrowser) {
     gBrowser.selectedTab = gBrowser.addTab("chrome://browser/content/devtools/connect.xhtml");
@@ -369,16 +379,21 @@ let gDevToolsBrowser = {
    *
    * @param {XULDocument} doc
    *        The document to which menuitems and handlers are to be added
    */
   registerBrowserWindow: function DT_registerBrowserWindow(win) {
     gDevToolsBrowser._trackedBrowserWindows.add(win);
     gDevToolsBrowser._addAllToolsToMenu(win.document);
 
+    if (this._isFirebugInstalled()) {
+      let broadcaster = win.document.getElementById("devtoolsMenuBroadcaster_DevToolbox");
+      broadcaster.removeAttribute("key");
+    }
+
     let tabContainer = win.document.getElementById("tabbrowser-tabs")
     tabContainer.addEventListener("TabSelect",
                                   gDevToolsBrowser._updateMenuCheckbox, false);
   },
 
   /**
    * Add a <key> to <keyset id="devtoolsKeyset">.
    * Appending a <key> element is not always enough. The <keyset> needs
@@ -387,25 +402,37 @@ let gDevToolsBrowser = {
    *
    * @param {XULDocument} doc
    *        The document to which keys are to be added
    * @param {XULElement} or {DocumentFragment} keys
    *        Keys to add
    */
   attachKeybindingsToBrowser: function DT_attachKeybindingsToBrowser(doc, keys) {
     let devtoolsKeyset = doc.getElementById("devtoolsKeyset");
+
     if (!devtoolsKeyset) {
       devtoolsKeyset = doc.createElement("keyset");
       devtoolsKeyset.setAttribute("id", "devtoolsKeyset");
     }
     devtoolsKeyset.appendChild(keys);
     let mainKeyset = doc.getElementById("mainKeyset");
     mainKeyset.parentNode.insertBefore(devtoolsKeyset, mainKeyset);
   },
 
+
+  /**
+   * Detect the presence of a Firebug.
+   *
+   * @return promise
+   */
+  _isFirebugInstalled: function DT_isFirebugInstalled() {
+    let bootstrappedAddons = Services.prefs.getCharPref("extensions.bootstrappedAddons");
+    return bootstrappedAddons.indexOf("firebug@software.joehewitt.com") != -1;
+  },
+
   /**
    * Add the menuitem for a tool to all open browser windows.
    *
    * @param {object} toolDefinition
    *        properties of the tool to add
    */
   _addToolToWindows: function DT_addToolToWindows(toolDefinition) {
     // No menu item or global shortcut is required for options panel.
@@ -720,16 +747,17 @@ let gDevToolsBrowser = {
   /**
    * All browser windows have been closed, tidy up remaining objects.
    */
   destroy: function() {
     gDevTools.off("toolbox-ready", gDevToolsBrowser._connectToProfiler);
     Services.obs.removeObserver(gDevToolsBrowser.destroy, "quit-application");
   },
 }
+
 this.gDevToolsBrowser = gDevToolsBrowser;
 
 gDevTools.on("tool-registered", function(ev, toolId) {
   let toolDefinition = gDevTools._tools.get(toolId);
   gDevToolsBrowser._addToolToWindows(toolDefinition);
 });
 
 gDevTools.on("tool-unregistered", function(ev, toolId) {
--- a/browser/devtools/framework/test/Makefile.in
+++ b/browser/devtools/framework/test/Makefile.in
@@ -25,11 +25,12 @@ MOCHITEST_BROWSER_FILES = \
 		browser_toolbox_tabsswitch_shortcuts.js \
 		browser_toolbox_window_title_changes.js \
 		browser_toolbox_options.js \
 		browser_toolbox_options_disablejs.js \
 		browser_toolbox_options_disablejs.html \
 		browser_toolbox_options_disablejs_iframe.html \
 		browser_toolbox_highlight.js \
 		browser_toolbox_raise.js \
+		browser_keybindings.js \
 		$(NULL)
 
 include $(topsrcdir)/config/rules.mk
new file mode 100644
--- /dev/null
+++ b/browser/devtools/framework/test/browser_keybindings.js
@@ -0,0 +1,119 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Tests that the keybindings for opening and closing the inspector work as expected
+// Can probably make this a shared test that tests all of the tools global keybindings
+
+function test()
+{
+  waitForExplicitFinish();
+
+  let doc;
+  let node;
+  let inspector;
+  let keysetMap = { };
+
+  gBrowser.selectedTab = gBrowser.addTab();
+  gBrowser.selectedBrowser.addEventListener("load", function onload() {
+    gBrowser.selectedBrowser.removeEventListener("load", onload, true);
+    doc = content.document;
+    waitForFocus(setupKeyBindingsTest, content);
+  }, true);
+
+  content.location = "data:text/html,<html><head><title>Test for the " +
+                     "highlighter keybindings</title></head><body>" +
+                     "<h1>Keybindings!</h1></body></html>";
+
+  function buildDevtoolsKeysetMap(keyset) {
+    [].forEach.call(keyset.querySelectorAll("key"), function(key) {
+
+      if (!key.getAttribute("key")) {
+        return;
+      }
+
+      let modifiers = key.getAttribute("modifiers");
+
+      keysetMap[key.id.split("_")[1]] = {
+        key: key.getAttribute("key"),
+        modifiers: modifiers,
+        modifierOpt: {
+          shiftKey: modifiers.match("shift"),
+          ctrlKey: modifiers.match("ctrl"),
+          altKey: modifiers.match("alt"),
+          metaKey: modifiers.match("meta"),
+          accelKey: modifiers.match("accel")
+        },
+        synthesizeKey: function() {
+          EventUtils.synthesizeKey(this.key, this.modifierOpt);
+        }
+      }
+    });
+  }
+
+  function setupKeyBindingsTest()
+  {
+    for (let win of gDevToolsBrowser._trackedBrowserWindows) {
+      buildDevtoolsKeysetMap(win.document.getElementById("devtoolsKeyset"));
+    }
+
+    gDevTools.once("toolbox-ready", (e, toolbox) => {
+      inspectorShouldBeOpenAndHighlighting(toolbox.getCurrentPanel(), toolbox)
+    });
+
+    keysetMap.inspector.synthesizeKey();
+  }
+
+  function inspectorShouldBeOpenAndHighlighting(aInspector, aToolbox)
+  {
+    is (aToolbox.currentToolId, "inspector", "Correct tool has been loaded");
+    is (aInspector.highlighter.locked, true, "Highlighter should be locked");
+
+    aInspector.highlighter.once("unlocked", () => {
+      is (aInspector.highlighter.locked, false, "Highlighter should be unlocked");
+      keysetMap.inspector.synthesizeKey();
+      is (aInspector.highlighter.locked, true, "Highlighter should be locked");
+      keysetMap.inspector.synthesizeKey();
+      is (aInspector.highlighter.locked, false, "Highlighter should be unlocked");
+      keysetMap.inspector.synthesizeKey();
+      is (aInspector.highlighter.locked, true, "Highlighter should be locked");
+
+      aToolbox.once("webconsole-ready", (e, panel) => {
+        webconsoleShouldBeSelected(aToolbox, panel);
+      });
+      keysetMap.webconsole.synthesizeKey();
+    });
+  }
+
+  function webconsoleShouldBeSelected(aToolbox, panel)
+  {
+      is (aToolbox.currentToolId, "webconsole");
+
+      aToolbox.once("jsdebugger-ready", (e, panel) => {
+        jsdebuggerShouldBeSelected(aToolbox, panel);
+      });
+      keysetMap.jsdebugger.synthesizeKey();
+  }
+
+  function jsdebuggerShouldBeSelected(aToolbox, panel)
+  {
+      is (aToolbox.currentToolId, "jsdebugger");
+
+      aToolbox.once("netmonitor-ready", (e, panel) => {
+        netmonitorShouldBeSelected(aToolbox, panel);
+      });
+
+      keysetMap.netmonitor.synthesizeKey();
+  }
+
+  function netmonitorShouldBeSelected(aToolbox, panel)
+  {
+      is (aToolbox.currentToolId, "netmonitor");
+      finishUp();
+  }
+
+  function finishUp() {
+    doc = node = inspector = keysetMap = null;
+    gBrowser.removeCurrentTab();
+    finish();
+  }
+}
--- a/browser/devtools/framework/toolbox.js
+++ b/browser/devtools/framework/toolbox.js
@@ -259,23 +259,40 @@ Toolbox.prototype = {
           key.setAttribute("keycode", toolDefinition.key);
         } else {
           key.setAttribute("key", toolDefinition.key);
         }
 
         key.setAttribute("modifiers", toolDefinition.modifiers);
         key.setAttribute("oncommand", "void(0);"); // needed. See bug 371900
         key.addEventListener("command", function(toolId) {
-          this.selectTool(toolId);
+          this.selectTool(toolId).then(() => {
+              this.fireCustomKey(toolId);
+          });
         }.bind(this, id), true);
         doc.getElementById("toolbox-keyset").appendChild(key);
       }
     }
   },
 
+
+  /**
+   * Handle any custom key events.  Returns true if there was a custom key binding run
+   * @param {string} toolId
+   *        Which tool to run the command on (skip if not current)
+   */
+  fireCustomKey: function TBOX_fireCustomKey(toolId) {
+    let tools = gDevTools.getToolDefinitionMap();
+    let activeToolDefinition = tools.get(toolId);
+
+    if (activeToolDefinition.onkey && this.currentToolId === toolId) {
+        activeToolDefinition.onkey(this.getCurrentPanel());
+    }
+  },
+
   /**
    * Build the buttons for changing hosts. Called every time
    * the host changes.
    */
   _buildDockButtons: function TBOX_createDockButtons() {
     let dockBox = this.doc.getElementById("toolbox-dock-buttons");
 
     while (dockBox.firstChild) {
--- a/browser/devtools/inspector/highlighter.js
+++ b/browser/devtools/inspector/highlighter.js
@@ -124,18 +124,16 @@ Highlighter.prototype = {
     // Insert the highlighter right after the browser
     stack.insertBefore(this.highlighterContainer, stack.childNodes[1]);
 
     this.buildInfobar(controlsBox);
 
     this.transitionDisabler = null;
     this.pageEventsMuter = null;
 
-    this.unlockAndFocus();
-
     this.selection.on("new-node", this.highlight);
     this.selection.on("new-node", this.updateInfobar);
     this.selection.on("pseudoclass", this.updateInfobar);
     this.selection.on("attribute-changed", this.updateInfobar);
 
     this.onToolSelected = function(event, id) {
       if (id != "inspector") {
         this.chromeWin.clearTimeout(this.pageEventsMuter);
--- a/browser/devtools/inspector/inspector-panel.js
+++ b/browser/devtools/inspector/inspector-panel.js
@@ -132,20 +132,16 @@ InspectorPanel.prototype = {
     this.isReady = false;
 
     this.once("markuploaded", function() {
       this.isReady = true;
 
       // All the components are initialized. Let's select a node.
       this._selection.setNodeFront(defaultSelection);
 
-      if (this.highlighter) {
-        this.highlighter.unlock();
-      }
-
       this.markup.expandNode(this.selection.nodeFront);
 
       this.emit("ready");
       deferred.resolve(this);
     }.bind(this));
 
     this.setupSearchBox();
     this.setupSidebar();
--- a/browser/devtools/inspector/selector-search.js
+++ b/browser/devtools/inspector/selector-search.js
@@ -1,21 +1,18 @@
 /* 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/. */
 
 "use strict";
 
-const {Cu} = require("chrome");
 const EventEmitter = require("devtools/shared/event-emitter");
 const promise = require("sdk/core/promise");
 
-loader.lazyGetter(this, "AutocompletePopup", () => {
-  return Cu.import("resource:///modules/devtools/AutocompletePopup.jsm", {}).AutocompletePopup;
-});
+loader.lazyGetter(this, "AutocompletePopup", () => require("devtools/shared/autocomplete-popup").AutocompletePopup);
 
 // Maximum number of selector suggestions shown in the panel.
 const MAX_SUGGESTIONS = 15;
 
 /**
  * Converts any input box on a page to a CSS selector search and suggestion box.
  *
  * @constructor
--- a/browser/devtools/inspector/test/browser_inspector_bug_665880.js
+++ b/browser/devtools/inspector/test/browser_inspector_bug_665880.js
@@ -24,16 +24,17 @@ function test()
     objectNode = doc.querySelector("object");
     ok(objectNode, "we have the object node");
     openInspector(runObjectInspectionTest);
   }
 
   function runObjectInspectionTest(inspector)
   {
     inspector.highlighter.once("locked", performTestComparison);
+    inspector.highlighter.unlock();
     inspector.selection.setNode(objectNode, "");
   }
 
   function performTestComparison()
   {
     is(getActiveInspector().selection.node, objectNode, "selection matches node");
     let target = TargetFactory.forTab(gBrowser.selectedTab);
     executeSoon(function() {
--- a/browser/devtools/inspector/test/browser_inspector_bug_674871.js
+++ b/browser/devtools/inspector/test/browser_inspector_bug_674871.js
@@ -45,16 +45,17 @@ function test()
     iframeBodyNode = iframeNode.contentDocument.querySelector("body");
     ok(iframeNode, "we have the iframe node");
     ok(iframeBodyNode, "we have the body node");
     openInspector(runTests);
   }
 
   function runTests(inspector)
   {
+    inspector.highlighter.unlock();
     executeSoon(function() {
       inspector.highlighter.once("highlighting", isTheIframeSelected);
       moveMouseOver(iframeNode, 1, 1);
     });
   }
 
   function isTheIframeSelected()
   {
--- a/browser/devtools/inspector/test/browser_inspector_iframeTest.js
+++ b/browser/devtools/inspector/test/browser_inspector_iframeTest.js
@@ -46,16 +46,17 @@ function createDocument()
 function moveMouseOver(aElement)
 {
   EventUtils.synthesizeMouse(aElement, 2, 2, {type: "mousemove"},
     aElement.ownerDocument.defaultView);
 }
 
 function runIframeTests()
 {
+  getActiveInspector().highlighter.unlock();
   getActiveInspector().selection.once("new-node", performTestComparisons1);
   moveMouseOver(div1)
 }
 
 function performTestComparisons1()
 {
   let i = getActiveInspector();
   is(i.selection.node, div1, "selection matches div1 node");
--- a/browser/devtools/inspector/test/browser_inspector_scrolling.js
+++ b/browser/devtools/inspector/test/browser_inspector_scrolling.js
@@ -30,16 +30,17 @@ function createDocument()
 }
 
 function inspectNode(aInspector)
 {
   inspector = aInspector;
 
   inspector.highlighter.once("locked", performScrollingTest);
   executeSoon(function() {
+    inspector.highlighter.unlock();
     inspector.selection.setNode(div, "");
   });
 }
 
 function performScrollingTest()
 {
   executeSoon(function() {
     EventUtils.synthesizeWheel(div, 10, 10,
--- a/browser/devtools/jar.mn
+++ b/browser/devtools/jar.mn
@@ -7,18 +7,17 @@ browser.jar:
     content/browser/devtools/widgets/VariablesView.xul                 (shared/widgets/VariablesView.xul)
     content/browser/devtools/markup-view.xhtml                         (markupview/markup-view.xhtml)
     content/browser/devtools/markup-view.css                           (markupview/markup-view.css)
     content/browser/devtools/netmonitor.xul                            (netmonitor/netmonitor.xul)
     content/browser/devtools/netmonitor.css                            (netmonitor/netmonitor.css)
     content/browser/devtools/netmonitor-controller.js                  (netmonitor/netmonitor-controller.js)
     content/browser/devtools/netmonitor-view.js                        (netmonitor/netmonitor-view.js)
     content/browser/devtools/NetworkPanel.xhtml                        (webconsole/NetworkPanel.xhtml)
-    content/browser/devtools/webconsole.js                             (webconsole/webconsole.js)
-*   content/browser/devtools/webconsole.xul                            (webconsole/webconsole.xul)
+    content/browser/devtools/webconsole.xul                            (webconsole/webconsole.xul)
 *   content/browser/devtools/scratchpad.xul                            (scratchpad/scratchpad.xul)
     content/browser/devtools/scratchpad.js                             (scratchpad/scratchpad.js)
     content/browser/devtools/splitview.css                             (shared/splitview.css)
     content/browser/devtools/theme-switching.js                        (shared/theme-switching.js)
     content/browser/devtools/styleeditor.xul                           (styleeditor/styleeditor.xul)
     content/browser/devtools/styleeditor.css                           (styleeditor/styleeditor.css)
     content/browser/devtools/computedview.xhtml                        (styleinspector/computedview.xhtml)
     content/browser/devtools/cssruleview.xhtml                         (styleinspector/cssruleview.xhtml)
--- a/browser/devtools/main.js
+++ b/browser/devtools/main.js
@@ -14,20 +14,22 @@ Object.defineProperty(exports, "Toolbox"
   get: () => require("devtools/framework/toolbox").Toolbox
 });
 Object.defineProperty(exports, "TargetFactory", {
   get: () => require("devtools/framework/target").TargetFactory
 });
 
 loader.lazyGetter(this, "osString", () => Cc["@mozilla.org/xre/app-info;1"].getService(Ci.nsIXULRuntime).OS);
 
+let events = require("sdk/system/events");
+
 // Panels
 loader.lazyGetter(this, "OptionsPanel", function() require("devtools/framework/toolbox-options").OptionsPanel);
 loader.lazyGetter(this, "InspectorPanel", function() require("devtools/inspector/inspector-panel").InspectorPanel);
-loader.lazyImporter(this, "WebConsolePanel", "resource:///modules/WebConsolePanel.jsm");
+loader.lazyGetter(this, "WebConsolePanel", function() require("devtools/webconsole/panel").WebConsolePanel);
 loader.lazyImporter(this, "DebuggerPanel", "resource:///modules/devtools/DebuggerPanel.jsm");
 loader.lazyImporter(this, "StyleEditorPanel", "resource:///modules/devtools/StyleEditorPanel.jsm");
 loader.lazyGetter(this, "ProfilerPanel", function() require("devtools/profiler/panel"));
 loader.lazyImporter(this, "NetMonitorPanel", "resource:///modules/devtools/NetMonitorPanel.jsm");
 
 // Strings
 const toolboxProps = "chrome://browser/locale/devtools/toolbox.properties";
 const inspectorProps = "chrome://browser/locale/devtools/inspector.properties";
@@ -90,16 +92,23 @@ Tools.inspector = {
   key: l10n("inspector.commandkey", inspectorStrings),
   ordinal: 2,
   modifiers: osString == "Darwin" ? "accel,alt" : "accel,shift",
   icon: "chrome://browser/skin/devtools/tool-inspector.png",
   url: "chrome://browser/content/devtools/inspector/inspector.xul",
   label: l10n("inspector.label", inspectorStrings),
   tooltip: l10n("inspector.tooltip", inspectorStrings),
 
+  preventClosingOnKey: true,
+  onkey: function(panel) {
+    if (panel.highlighter) {
+      panel.highlighter.toggleLockState();
+    }
+  },
+
   isTargetSupported: function(target) {
     return !target.isRemote;
   },
 
   build: function(iframeWindow, toolbox) {
     let panel = new InspectorPanel(iframeWindow, toolbox);
     return panel.open();
   }
@@ -216,16 +225,18 @@ var unloadObserver = {
       for (let definition of gDevTools.getToolDefinitionArray()) {
         gDevTools.unregisterTool(definition.id);
       }
     }
   }
 };
 Services.obs.addObserver(unloadObserver, "sdk:loader:destroy", false);
 
+events.emit("devtools-loaded", {});
+
 /**
  * Lookup l10n string from a string bundle.
  *
  * @param {string} name
  *        The key to lookup.
  * @param {StringBundle} bundle
  *        The key to lookup.
  * @returns A localized version of the given key.
--- a/browser/devtools/markupview/markup-view.js
+++ b/browser/devtools/markupview/markup-view.js
@@ -16,19 +16,17 @@ let {UndoStack} = require("devtools/shar
 let EventEmitter = require("devtools/shared/event-emitter");
 let {editableField, InplaceEditor} = require("devtools/shared/inplace-editor");
 let promise = require("sdk/core/promise");
 
 Cu.import("resource:///modules/devtools/LayoutHelpers.jsm");
 Cu.import("resource://gre/modules/devtools/Templater.jsm");
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
-XPCOMUtils.defineLazyGetter(this, "AutocompletePopup", function() {
-  return Cu.import("resource:///modules/devtools/AutocompletePopup.jsm", {}).AutocompletePopup;
-});
+loader.lazyGetter(this, "AutocompletePopup", () => require("devtools/shared/autocomplete-popup").AutocompletePopup);
 
 /**
  * Vocabulary for the purposes of this file:
  *
  * MarkupContainer - the structure that holds an editor and its
  *  immediate children in the markup panel.
  * Node - A content node.
  * object.elt - A UI element in the markup panel.
@@ -156,16 +154,24 @@ MarkupView.prototype = {
 
     // Ignore keystrokes that originated in editors.
     if (aEvent.target.tagName.toLowerCase() === "input" ||
         aEvent.target.tagName.toLowerCase() === "textarea") {
       return;
     }
 
     switch(aEvent.keyCode) {
+      case Ci.nsIDOMKeyEvent.DOM_VK_H:
+        let node = this._selectedContainer.node;
+        if (node.hidden) {
+          this.walker.unhideNode(node).then(() => this.nodeChanged(node));
+        } else {
+          this.walker.hideNode(node).then(() => this.nodeChanged(node));
+        }
+        break;
       case Ci.nsIDOMKeyEvent.DOM_VK_DELETE:
       case Ci.nsIDOMKeyEvent.DOM_VK_BACK_SPACE:
         this.deleteNode(this._selectedContainer.node);
         break;
       case Ci.nsIDOMKeyEvent.DOM_VK_HOME:
         let rootContainer = this._containers.get(this._rootNode);
         this.navigate(rootContainer.children.firstChild.container);
         break;
@@ -518,17 +524,17 @@ MarkupView.prototype = {
     }
   },
 
   /**
    * Called when the markup panel initiates a change on a node.
    */
   nodeChanged: function MT_nodeChanged(aNode)
   {
-    if (aNode === this._inspector.selection) {
+    if (aNode === this._inspector.selection.nodeFront) {
       this._inspector.change("markupview");
     }
   },
 
   /**
    * Check if the current selection is a descendent of the container.
    * if so, make sure it's among the visible set for the container,
    * and set the dirty flag if needed.
--- a/browser/devtools/netmonitor/netmonitor-controller.js
+++ b/browser/devtools/netmonitor/netmonitor-controller.js
@@ -14,18 +14,26 @@ Cu.import("resource:///modules/source-ed
 Cu.import("resource:///modules/devtools/shared/event-emitter.js");
 Cu.import("resource:///modules/devtools/SideMenuWidget.jsm");
 Cu.import("resource:///modules/devtools/VariablesView.jsm");
 Cu.import("resource:///modules/devtools/ViewHelpers.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "PluralForm",
   "resource://gre/modules/PluralForm.jsm");
 
-XPCOMUtils.defineLazyModuleGetter(this, "NetworkHelper",
-  "resource://gre/modules/devtools/NetworkHelper.jsm");
+XPCOMUtils.defineLazyModuleGetter(this, "devtools",
+  "resource://gre/modules/devtools/Loader.jsm");
+
+Object.defineProperty(this, "NetworkHelper", {
+  get: function() {
+    return devtools.require("devtools/toolkit/webconsole/network-helper");
+  },
+  configurable: true,
+  enumerable: true
+});
 
 XPCOMUtils.defineLazyServiceGetter(this, "clipboardHelper",
   "@mozilla.org/widget/clipboardhelper;1", "nsIClipboardHelper");
 
 const NET_STRINGS_URI = "chrome://browser/locale/devtools/netmonitor.properties";
 const LISTENERS = [ "NetworkActivity" ];
 const NET_PREFS = { "NetworkMonitor.saveRequestAndResponseBodies": true };
 
--- a/browser/devtools/profiler/test/head.js
+++ b/browser/devtools/profiler/test/head.js
@@ -14,19 +14,16 @@ Cu.import("resource:///modules/devtools/
 let gDevTools = temp.gDevTools;
 
 Cu.import("resource://gre/modules/devtools/Loader.jsm", temp);
 let TargetFactory = temp.devtools.TargetFactory;
 
 Cu.import("resource://gre/modules/devtools/dbg-server.jsm", temp);
 let DebuggerServer = temp.DebuggerServer;
 
-Cu.import("resource:///modules/HUDService.jsm", temp);
-let HUDService = temp.HUDService;
-
 // Import the GCLI test helper
 let testDir = gTestPath.substr(0, gTestPath.lastIndexOf("/"));
 Services.scriptloader.loadSubScript(testDir + "../../../commandline/test/helpers.js", this);
 
 registerCleanupFunction(function () {
   helpers = null;
   Services.prefs.clearUserPref(PROFILER_ENABLED);
   Services.prefs.clearUserPref(REMOTE_ENABLED);
--- a/browser/devtools/scratchpad/test/browser_scratchpad_bug_661762_wrong_window_focus.js
+++ b/browser/devtools/scratchpad/test/browser_scratchpad_bug_661762_wrong_window_focus.js
@@ -1,16 +1,12 @@
 /* vim:set ts=2 sw=2 sts=2 et: */
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
-let tempScope = {};
-Cu.import("resource:///modules/HUDService.jsm", tempScope);
-let HUDService = tempScope.HUDService;
-
 function test()
 {
   waitForExplicitFinish();
 
   // To test for this bug we open a Scratchpad window, save its
   // reference and then open another one. This way the first window
   // loses its focus.
   //
@@ -38,17 +34,17 @@ function test()
           let hud = HUDService.getHudReferenceById(subj.data);
           hud.jsterm.clearOutput(true);
           executeSoon(testFocus.bind(null, sw, hud));
         }
 
         Services.obs.
           addObserver(onWebConsoleOpen, "web-console-created", false);
 
-        HUDService.consoleUI.toggleHUD();
+        HUDService.toggleWebConsole();
       });
     });
   }, true);
 
   content.location = "data:text/html;charset=utf8,<p>test window focus for Scratchpad.";
 }
 
 function testFocus(sw, hud) {
--- a/browser/devtools/shared/DeveloperToolbar.jsm
+++ b/browser/devtools/shared/DeveloperToolbar.jsm
@@ -20,19 +20,16 @@ XPCOMUtils.defineLazyModuleGetter(this, 
                                   "resource://gre/modules/devtools/Console.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "gcli",
                                   "resource://gre/modules/devtools/gcli.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "CmdCommands",
                                   "resource:///modules/devtools/BuiltinCommands.jsm");
 
-XPCOMUtils.defineLazyModuleGetter(this, "ConsoleServiceListener",
-                                  "resource://gre/modules/devtools/WebConsoleUtils.jsm");
-
 XPCOMUtils.defineLazyModuleGetter(this, "PluralForm",
                                   "resource://gre/modules/PluralForm.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "devtools",
                                   "resource://gre/modules/devtools/Loader.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "require",
                                   "resource://gre/modules/devtools/Require.jsm");
@@ -50,16 +47,24 @@ XPCOMUtils.defineLazyGetter(this, "prefB
 XPCOMUtils.defineLazyGetter(this, "toolboxStrings", function () {
   return Services.strings.createBundle("chrome://browser/locale/devtools/toolbox.properties");
 });
 
 let Telemetry = devtools.require("devtools/shared/telemetry");
 
 const converters = require("gcli/converters");
 
+Object.defineProperty(this, "ConsoleServiceListener", {
+  get: function() {
+    return devtools.require("devtools/toolkit/webconsole/utils").ConsoleServiceListener;
+  },
+  configurable: true,
+  enumerable: true
+});
+
 /**
  * A collection of utilities to help working with commands
  */
 let CommandUtils = {
   /**
    * Read a toolbarSpec from preferences
    * @param aPref The name of the preference to read
    */
@@ -395,16 +400,20 @@ DeveloperToolbar.prototype._onload = fun
 
   let tabbrowser = this._chromeWindow.getBrowser();
   tabbrowser.tabContainer.addEventListener("TabSelect", this, false);
   tabbrowser.tabContainer.addEventListener("TabClose", this, false);
   tabbrowser.addEventListener("load", this, true);
   tabbrowser.addEventListener("beforeunload", this, true);
 
   this._initErrorsCount(tabbrowser.selectedTab);
+  this._devtoolsUnloaded = this._devtoolsUnloaded.bind(this);
+  this._devtoolsLoaded = this._devtoolsLoaded.bind(this);
+  Services.obs.addObserver(this._devtoolsUnloaded, "devtools-unloaded", false);
+  Services.obs.addObserver(this._devtoolsLoaded, "devtools-loaded", false);
 
   this._element.hidden = false;
 
   if (aFocus) {
     this._input.focus();
   }
 
   this._notify(NOTIFICATIONS.SHOW);
@@ -423,16 +432,36 @@ DeveloperToolbar.prototype._onload = fun
 
   if (!DeveloperToolbar.introShownThisSession) {
     this.display.maybeShowIntro();
     DeveloperToolbar.introShownThisSession = true;
   }
 };
 
 /**
+ * The devtools-unloaded event handler.
+ * @private
+ */
+DeveloperToolbar.prototype._devtoolsUnloaded = function DT__devtoolsUnloaded()
+{
+  let tabbrowser = this._chromeWindow.getBrowser();
+  Array.prototype.forEach.call(tabbrowser.tabs, this._stopErrorsCount, this);
+};
+
+/**
+ * The devtools-loaded event handler.
+ * @private
+ */
+DeveloperToolbar.prototype._devtoolsLoaded = function DT__devtoolsLoaded()
+{
+  let tabbrowser = this._chromeWindow.getBrowser();
+  this._initErrorsCount(tabbrowser.selectedTab);
+};
+
+/**
  * Initialize the listeners needed for tracking the number of errors for a given
  * tab.
  *
  * @private
  * @param nsIDOMNode aTab the xul:tab for which you want to track the number of
  * errors.
  */
 DeveloperToolbar.prototype._initErrorsCount = function DT__initErrorsCount(aTab)
@@ -518,16 +547,18 @@ DeveloperToolbar.prototype.destroy = fun
   }
 
   let tabbrowser = this._chromeWindow.getBrowser();
   tabbrowser.tabContainer.removeEventListener("TabSelect", this, false);
   tabbrowser.tabContainer.removeEventListener("TabClose", this, false);
   tabbrowser.removeEventListener("load", this, true);
   tabbrowser.removeEventListener("beforeunload", this, true);
 
+  Services.obs.removeObserver(this._devtoolsUnloaded, "devtools-unloaded");
+  Services.obs.removeObserver(this._devtoolsLoaded, "devtools-loaded");
   Array.prototype.forEach.call(tabbrowser.tabs, this._stopErrorsCount, this);
 
   this.display.focusManager.removeMonitoredElement(this.outputPanel._frame);
   this.display.focusManager.removeMonitoredElement(this._element);
 
   this.display.onVisibilityChange.remove(this.outputPanel._visibilityChanged, this.outputPanel);
   this.display.onVisibilityChange.remove(this.tooltipPanel._visibilityChanged, this.tooltipPanel);
   this.display.onOutput.remove(this.outputPanel._outputChanged, this.outputPanel);
rename from browser/devtools/shared/AutocompletePopup.jsm
rename to browser/devtools/shared/autocomplete-popup.js
--- a/browser/devtools/shared/AutocompletePopup.jsm
+++ b/browser/devtools/shared/autocomplete-popup.js
@@ -1,27 +1,20 @@
 /* vim: set ft=javascript ts=2 et sw=2 tw=80: */
 /* 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/. */
 
-const Cu = Components.utils;
-const Ci = Components.interfaces;
+"use strict";
 
-// The XUL and XHTML namespace.
+const {Cc, Ci, Cu} = require("chrome");
 const XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
 
-Cu.import("resource://gre/modules/Services.jsm");
-Cu.import("resource://gre/modules/XPCOMUtils.jsm");
-
-XPCOMUtils.defineLazyGetter(this, "gDevTools", function() {
-  return Cu.import("resource:///modules/devtools/gDevTools.jsm", {}).gDevTools;
-});
-
-this.EXPORTED_SYMBOLS = ["AutocompletePopup"];
+loader.lazyImporter(this, "Services", "resource://gre/modules/Services.jsm");
+loader.lazyImporter(this, "gDevTools", "resource:///modules/devtools/gDevTools.jsm");
 
 /**
  * Autocomplete popup UI implementation.
  *
  * @constructor
  * @param nsIDOMDocument aDocument
  *        The document you want the popup attached to.
  * @param Object aOptions
@@ -33,17 +26,16 @@ this.EXPORTED_SYMBOLS = ["AutocompletePo
  *        - autoSelect {Boolean} Boolean to allow the first entry of the popup
  *                     panel to be automatically selected when the popup shows.
  *        - fixedWidth {Boolean} Boolean to control dynamic width of the popup.
  *        - direction {String} The direction of the text in the panel. rtl or ltr
  *        - onSelect {String} The select event handler for the richlistbox
  *        - onClick {String} The click event handler for the richlistbox.
  *        - onKeypress {String} The keypress event handler for the richlistitems.
  */
-this.AutocompletePopup =
 function AutocompletePopup(aDocument, aOptions = {})
 {
   this._document = aDocument;
 
   this.fixedWidth = aOptions.fixedWidth || false;
   this.autoSelect = aOptions.autoSelect || false;
   this.position = aOptions.position || "after_start";
   this.direction = aOptions.direction || "ltr";
@@ -112,16 +104,17 @@ function AutocompletePopup(aDocument, aO
   if (this.onClick) {
     this._list.addEventListener("click", this.onClick, false);
   }
 
   if (this.onKeypress) {
     this._list.addEventListener("keypress", this.onKeypress, false);
   }
 }
+exports.AutocompletePopup = AutocompletePopup;
 
 AutocompletePopup.prototype = {
   _document: null,
   _panel: null,
   _list: null,
 
   // Event handlers.
   onSelect: null,
@@ -263,32 +256,38 @@ AutocompletePopup.prototype = {
 
   /**
    * Update the panel size to fit the content.
    *
    * @private
    */
   _updateSize: function AP__updateSize()
   {
-    // We need the dispatch to allow the content to reflow. Attempting to
-    // update the richlistbox size too early does not work.
-    Services.tm.currentThread.dispatch({ run: () => {
-      if (!this._panel) {
-        return;
-      }
-      this._list.width = this._panel.clientWidth + this._scrollbarWidth;
-      // Height change is required, otherwise the panel is drawn at an offset
-      // the first time.
-      this._list.height = this._list.clientHeight;
-      // This brings the panel back at right position.
-      this._list.top = 0;
-      // Changing panel height might make the selected item out of view, so
-      // bring it back to view.
-      this._list.ensureIndexIsVisible(this._list.selectedIndex);
-    }}, 0);
+    if (!this._panel) {
+      return;
+    }
+    // Flush the layout so that we get the latest height.
+    this._panel.boxObject.height;
+    let height = {};
+    this._list.scrollBoxObject.getScrolledSize({}, height);
+    // Change the width of the popup only if the scrollbar is visible.
+    if (height.value > this._panel.clientHeight) {
+       this._list.width = this._panel.clientWidth + this._scrollbarWidth;
+    }
+    // Height change is required, otherwise the panel is drawn at an offset
+    // the first time.
+    this._list.height = this._list.clientHeight;
+    // This brings the panel back at right position.
+    this._list.top = 0;
+    // Move the panel to -1,-1 to realign the popup with its anchor node when
+    // decreasing the panel height.
+    this._panel.moveTo(-1, -1);
+    // Changing panel height might make the selected item out of view, so
+    // bring it back to view.
+    this._list.ensureIndexIsVisible(this._list.selectedIndex);
   },
 
   /**
    * Clear all the items from the autocomplete list.
    */
   clearItems: function AP_clearItems()
   {
     // Reset the selectedIndex to -1 before clearing the list
--- a/browser/devtools/shared/test/browser_toolbar_webconsole_errors_count.js
+++ b/browser/devtools/shared/test/browser_toolbar_webconsole_errors_count.js
@@ -2,18 +2,16 @@
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 // Tests that the developer toolbar errors count works properly.
 
 function test() {
   const TEST_URI = "http://example.com/browser/browser/devtools/shared/test/" +
                    "browser_toolbar_webconsole_errors_count.html";
 
-  let HUDService = Cu.import("resource:///modules/HUDService.jsm",
-                             {}).HUDService;
   let gDevTools = Cu.import("resource:///modules/devtools/gDevTools.jsm",
                              {}).gDevTools;
 
   let webconsole = document.getElementById("developer-toolbar-toolbox-button");
   let tab1, tab2;
 
   Services.prefs.setBoolPref("javascript.options.strict", true);
 
--- a/browser/devtools/shared/widgets/SideMenuWidget.jsm
+++ b/browser/devtools/shared/widgets/SideMenuWidget.jsm
@@ -9,18 +9,26 @@ const Ci = Components.interfaces;
 const Cu = Components.utils;
 
 const ENSURE_SELECTION_VISIBLE_DELAY = 50; // ms
 
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource:///modules/devtools/ViewHelpers.jsm");
 Cu.import("resource:///modules/devtools/shared/event-emitter.js");
 
-XPCOMUtils.defineLazyModuleGetter(this, "NetworkHelper",
-  "resource://gre/modules/devtools/NetworkHelper.jsm");
+XPCOMUtils.defineLazyModuleGetter(this, "devtools",
+  "resource://gre/modules/devtools/Loader.jsm");
+
+Object.defineProperty(this, "NetworkHelper", {
+  get: function() {
+    return devtools.require("devtools/toolkit/webconsole/network-helper");
+  },
+  configurable: true,
+  enumerable: true
+});
 
 this.EXPORTED_SYMBOLS = ["SideMenuWidget"];
 
 /**
  * A simple side menu, with the ability of grouping menu items.
  * This widget should be used in tandem with the WidgetMethods in ViewHelpers.jsm
  *
  * @param nsIDOMNode aNode
@@ -624,17 +632,22 @@ SideMenuItem.prototype = {
     checkbox.setAttribute("tooltiptext", aAttachment.checkboxTooltip);
 
     if (aAttachment.checkboxState) {
       checkbox.setAttribute("checked", true);
     } else {
       checkbox.removeAttribute("checked");
     }
 
-    checkbox.addEventListener("command", function () {
+    // Stop the toggling of the checkbox from selecting the list item.
+    checkbox.addEventListener("mousedown", function (event) {
+      event.stopPropagation();
+    }, false);
+
+    checkbox.addEventListener("command", function (event) {
       ViewHelpers.dispatchEvent(checkbox, "check", {
         checked: checkbox.checked,
       });
     }, false);
 
     return checkbox;
   },
 
--- a/browser/devtools/shared/widgets/VariablesView.jsm
+++ b/browser/devtools/shared/widgets/VariablesView.jsm
@@ -18,21 +18,34 @@ const PAGE_SIZE_MAX_JUMPS = 30;
 const SEARCH_ACTION_MAX_DELAY = 300; // ms
 
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource:///modules/devtools/ViewHelpers.jsm");
 Cu.import("resource:///modules/devtools/shared/event-emitter.js");
 let promise = Cu.import("resource://gre/modules/commonjs/sdk/core/promise.js").Promise;
 
-XPCOMUtils.defineLazyModuleGetter(this, "NetworkHelper",
-  "resource://gre/modules/devtools/NetworkHelper.jsm");
-
-XPCOMUtils.defineLazyModuleGetter(this, "WebConsoleUtils",
-  "resource://gre/modules/devtools/WebConsoleUtils.jsm");
+XPCOMUtils.defineLazyModuleGetter(this, "devtools",
+  "resource://gre/modules/devtools/Loader.jsm");
+
+Object.defineProperty(this, "WebConsoleUtils", {
+  get: function() {
+    return devtools.require("devtools/toolkit/webconsole/utils").Utils;
+  },
+  configurable: true,
+  enumerable: true
+});
+
+Object.defineProperty(this, "NetworkHelper", {
+  get: function() {
+    return devtools.require("devtools/toolkit/webconsole/network-helper");
+  },
+  configurable: true,
+  enumerable: true
+});
 
 this.EXPORTED_SYMBOLS = ["VariablesView"];
 
 /**
  * Debugger localization strings.
  */
 const STR = Services.strings.createBundle(DBG_STRINGS_URI);
 
--- a/browser/devtools/shared/widgets/VariablesViewController.jsm
+++ b/browser/devtools/shared/widgets/VariablesViewController.jsm
@@ -7,17 +7,27 @@
 
 const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
 
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 let promise = Cu.import("resource://gre/modules/commonjs/sdk/core/promise.js").Promise;
 Cu.import("resource:///modules/devtools/VariablesView.jsm");
 Cu.import("resource:///modules/devtools/ViewHelpers.jsm");
-Cu.import("resource://gre/modules/devtools/WebConsoleUtils.jsm");
+
+XPCOMUtils.defineLazyModuleGetter(this, "devtools",
+  "resource://gre/modules/devtools/Loader.jsm");
+
+Object.defineProperty(this, "WebConsoleUtils", {
+  get: function() {
+    return devtools.require("devtools/toolkit/webconsole/utils").Utils;
+  },
+  configurable: true,
+  enumerable: true
+});
 
 XPCOMUtils.defineLazyGetter(this, "VARIABLES_SORTING_ENABLED", () =>
   Services.prefs.getBoolPref("devtools.debugger.ui.variables-sorting-enabled")
 );
 
 const MAX_LONG_STRING_LENGTH = 200000;
 
 this.EXPORTED_SYMBOLS = ["VariablesViewController"];
--- a/browser/devtools/styleeditor/StyleEditorUI.jsm
+++ b/browser/devtools/styleeditor/StyleEditorUI.jsm
@@ -144,17 +144,17 @@ StyleEditorUI.prototype = {
     showFilePicker(file, false, parentWindow, onFileSelected);
   },
 
   /**
    * Handler for debuggee's 'stylesheets-cleared' event. Remove all editors.
    */
   _onStyleSheetsCleared: function() {
     // remember selected sheet and line number for next load
-    if (this.selectedEditor) {
+    if (this.selectedEditor && this.selectedEditor.sourceEditor) {
       let href = this.selectedEditor.styleSheet.href;
       let {line, col} = this.selectedEditor.sourceEditor.getCaretPosition();
       this.selectStyleSheet(href, line, col);
     }
 
     this._clearStyleSheetEditors();
     this._view.removeAll();
 
--- a/browser/devtools/styleinspector/rule-view.js
+++ b/browser/devtools/styleinspector/rule-view.js
@@ -1886,11 +1886,9 @@ XPCOMUtils.defineLazyGetter(this, "_stri
   return Services.strings.createBundle(
     "chrome://browser/locale/devtools/styleinspector.properties");
 });
 
 XPCOMUtils.defineLazyGetter(this, "domUtils", function() {
   return Cc["@mozilla.org/inspector/dom-utils;1"].getService(Ci.inIDOMUtils);
 });
 
-XPCOMUtils.defineLazyGetter(this, "AutocompletePopup", function() {
-  return Cu.import("resource:///modules/devtools/AutocompletePopup.jsm", {}).AutocompletePopup;
-});
+loader.lazyGetter(this, "AutocompletePopup", () => require("devtools/shared/autocomplete-popup").AutocompletePopup);
--- a/browser/devtools/webconsole/Makefile.in
+++ b/browser/devtools/webconsole/Makefile.in
@@ -7,9 +7,9 @@ topsrcdir	= @top_srcdir@
 srcdir		= @srcdir@
 VPATH		= @srcdir@
 
 include $(DEPTH)/config/autoconf.mk
 
 include $(topsrcdir)/config/rules.mk
 
 libs::
-	$(NSINSTALL) $(srcdir)/*.js $(FINAL_TARGET)/modules/devtools/framework
+	$(NSINSTALL) $(srcdir)/*.js $(FINAL_TARGET)/modules/devtools/webconsole
new file mode 100644
--- /dev/null
+++ b/browser/devtools/webconsole/console-output.js
@@ -0,0 +1,311 @@
+/* vim: set ts=2 et sw=2 tw=80: */
+/* 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/. */
+
+"use strict";
+
+const Heritage = require("sdk/core/heritage");
+const XHTML_NS = "http://www.w3.org/1999/xhtml";
+const XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
+
+// Constants for compatibility with the Web Console output implementation before
+// bug 778766.
+// TODO: remove these once bug 778766 is fixed.
+const COMPAT = {
+  // The various categories of messages.
+  CATEGORIES: {
+    NETWORK: 0,
+    CSS: 1,
+    JS: 2,
+    WEBDEV: 3,
+    INPUT: 4,
+    OUTPUT: 5,
+    SECURITY: 6,
+  },
+
+  // The possible message severities.
+  SEVERITIES: {
+    ERROR: 0,
+    WARNING: 1,
+    INFO: 2,
+    LOG: 3,
+  },
+};
+
+/**
+ * The ConsoleOutput object is used to manage output of messages in the Web
+ * Console.
+ *
+ * @constructor
+ * @param object owner
+ *        The console output owner. This usually the WebConsoleFrame instance.
+ *        Any other object can be used, as long as it has the following
+ *        properties and methods:
+ *          - window
+ *          - document
+ *          - outputMessage(category, methodOrNode[, methodArguments])
+ *            TODO: this is needed temporarily, until bug 778766 is fixed.
+ */
+function ConsoleOutput(owner)
+{
+  this.owner = owner;
+  this._onFlushOutputMessage = this._onFlushOutputMessage.bind(this);
+}
+
+ConsoleOutput.prototype = {
+  /**
+   * The document that holds the output.
+   * @type DOMDocument
+   */
+  get document() this.owner.document,
+
+  /**
+   * The DOM window that holds the output.
+   * @type Window
+   */
+  get window() this.owner.window,
+
+  /**
+   * Add a message to output.
+   *
+   * @param object ...args
+   *        Any number of Message objects.
+   * @return this
+   */
+  addMessage: function(...args)
+  {
+    for (let msg of args) {
+      msg.init(this);
+      this.owner.outputMessage(msg._categoryCompat, this._onFlushOutputMessage,
+                               [msg]);
+    }
+    return this;
+  },
+
+  /**
+   * Message renderer used for compatibility with the current Web Console output
+   * implementation. This method is invoked for every message object that is
+   * flushed to output. The message object is initialized and rendered, then it
+   * is displayed.
+   *
+   * TODO: remove this method once bug 778766 is fixed.
+   *
+   * @private
+   * @param object message
+   *        The message object to render.
+   * @return DOMElement
+   *         The message DOM element that can be added to the console output.
+   */
+  _onFlushOutputMessage: function(message)
+  {
+    return message.render().element;
+  },
+
+  /**
+   * Destroy this ConsoleOutput instance.
+   */
+  destroy: function()
+  {
+    this.owner = null;
+  },
+}; // ConsoleOutput.prototype
+
+/**
+ * Message objects container.
+ * @type object
+ */
+let Messages = {};
+
+/**
+ * The BaseMessage object is used for all types of messages. Every kind of
+ * message should use this object as its base.
+ *
+ * @constructor
+ */
+Messages.BaseMessage = function()
+{
+  this.widgets = new Set();
+};
+
+Messages.BaseMessage.prototype = {
+  /**
+   * Reference to the ConsoleOutput owner.
+   *
+   * @type object|null
+   *       This is |null| if the message is not yet initialized.
+   */
+  output: null,
+
+  /**
+   * Reference to the parent message object, if this message is in a group or if
+   * it is otherwise owned by another message.
+   *
+   * @type object|null
+   */
+  parent: null,
+
+  /**
+   * Message DOM element.
+   *
+   * @type DOMElement|null
+   *       This is |null| if the message is not yet rendered.
+   */
+  element: null,
+
+  /**
+   * Tells if this message is visible or not.
+   * @type boolean
+   */
+  get visible() {
+    return this.element && this.element.parentNode;
+  },
+
+  /**
+   * Holds the text-only representation of the message.
+   * @type string
+   */
+  textContent: "",
+
+  /**
+   * Set of widgets included in this message.
+   * @type Set
+   */
+  widgets: null,
+
+  // Properties that allow compatibility with the current Web Console output
+  // implementation.
+  _elementClassCompat: "",
+  _categoryCompat: null,
+  _severityCompat: null,
+
+  /**
+   * Initialize the message.
+   *
+   * @param object output
+   *        The ConsoleOutput owner.
+   * @param object [parent=null]
+   *        Optional: a different message object that owns this instance.
+   * @return this
+   */
+  init: function(output, parent=null)
+  {
+    this.output = output;
+    this.parent = parent;
+    return this;
+  },
+
+  /**
+   * Render the message. After this method is invoked the |element| property
+   * will point to the DOM element of this message.
+   * @return this
+   */
+  render: function()
+  {
+    if (!this.element) {
+      this.element = this._renderCompat();
+    }
+    return this;
+  },
+
+  /**
+   * Prepare the message container for the Web Console, such that it is
+   * compatible with the current implementation.
+   * TODO: remove this once bug 778766.
+   */
+  _renderCompat: function()
+  {
+    let doc = this.output.document;
+    let container = doc.createElementNS(XUL_NS, "richlistitem");
+    container.setAttribute("id", "console-msg-" + gSequenceId());
+    container.setAttribute("class", "hud-msg-node " + this._elementClassCompat);
+    container.category = this._categoryCompat;
+    container.severity = this._severityCompat;
+    container.clipboardText = this.textContent;
+    container.timestamp = this.timestamp;
+    container._messageObject = this;
+
+    let body = doc.createElementNS(XUL_NS, "description");
+    body.flex = 1;
+    body.classList.add("webconsole-msg-body");
+    container.appendChild(body);
+
+    return container;
+  },
+}; // Messages.BaseMessage.prototype
+
+
+/**
+ * The NavigationMarker is used to show a page load event.
+ *
+ * @constructor
+ * @extends Messages.BaseMessage
+ * @param string url
+ *        The URL to display.
+ * @param number timestamp
+ *        The message date and time, milliseconds elapsed since 1 January 1970
+ *        00:00:00 UTC.
+ */
+Messages.NavigationMarker = function(url, timestamp)
+{
+  Messages.BaseMessage.apply(this, arguments);
+  this._url = url;
+  this.textContent = "------ " + url;
+  this.timestamp = timestamp;
+};
+
+Messages.NavigationMarker.prototype = Heritage.extend(Messages.BaseMessage.prototype,
+{
+  /**
+   * Message timestamp.
+   *
+   * @type number
+   *       Milliseconds elapsed since 1 January 1970 00:00:00 UTC.
+   */
+  timestamp: 0,
+
+  // Class names in order: category, severity then the class for the filter.
+  _elementClassCompat: "webconsole-msg-network webconsole-msg-info hud-networkinfo",
+  _categoryCompat: COMPAT.CATEGORIES.NETWORK,
+  _severityCompat: COMPAT.SEVERITIES.LOG,
+
+  /**
+   * Prepare the DOM element for this message.
+   * @return this
+   */
+  render: function()
+  {
+    if (this.element) {
+      return this;
+    }
+
+    let url = this._url;
+    let pos = url.indexOf("?");
+    if (pos > -1) {
+      url = url.substr(0, pos);
+    }
+
+    let doc = this.output.document;
+    let urlnode = doc.createElementNS(XHTML_NS, "span");
+    urlnode.className = "url";
+    urlnode.textContent = url;
+
+    // Add the text in the xul:description.webconsole-msg-body element.
+    let render = Messages.BaseMessage.prototype.render.bind(this);
+    render().element.firstChild.appendChild(urlnode);
+    this.element.classList.add("navigation-marker");
+    this.element.url = this._url;
+
+    return this;
+  },
+}); // Messages.NavigationMarker.prototype
+
+
+function gSequenceId()
+{
+  return gSequenceId.n++;
+}
+gSequenceId.n = 0;
+
+exports.ConsoleOutput = ConsoleOutput;
+exports.Messages = Messages;
rename from browser/devtools/webconsole/HUDService.jsm
rename to browser/devtools/webconsole/hudservice.js
--- a/browser/devtools/webconsole/HUDService.jsm
+++ b/browser/devtools/webconsole/hudservice.js
@@ -1,82 +1,68 @@
 /* -*- Mode: js2; js2-basic-offset: 2; indent-tabs-mode: nil; -*- */
 /* vim: set ft=javascript ts=2 et sw=2 tw=80: */
 /* 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/. */
 
 "use strict";
 
-const Cc = Components.classes;
-const Ci = Components.interfaces;
-const Cu = Components.utils;
-
-Cu.import("resource://gre/modules/XPCOMUtils.jsm");
+const {Cc, Ci, Cu} = require("chrome");
 
-XPCOMUtils.defineLazyModuleGetter(this, "gDevTools",
-    "resource:///modules/devtools/gDevTools.jsm");
-
-XPCOMUtils.defineLazyModuleGetter(this, "devtools",
-    "resource://gre/modules/devtools/Loader.jsm");
-
-XPCOMUtils.defineLazyModuleGetter(this, "Services",
-    "resource://gre/modules/Services.jsm");
+let WebConsoleUtils = require("devtools/toolkit/webconsole/utils").Utils;
+let Heritage = require("sdk/core/heritage");
 
-XPCOMUtils.defineLazyModuleGetter(this, "DebuggerServer",
-  "resource://gre/modules/devtools/dbg-server.jsm");
-
-XPCOMUtils.defineLazyModuleGetter(this, "DebuggerClient",
-  "resource://gre/modules/devtools/dbg-client.jsm");
-
-XPCOMUtils.defineLazyModuleGetter(this, "WebConsoleUtils",
-    "resource://gre/modules/devtools/WebConsoleUtils.jsm");
-
-XPCOMUtils.defineLazyModuleGetter(this, "promise",
-    "resource://gre/modules/commonjs/sdk/core/promise.js", "Promise");
-
-XPCOMUtils.defineLazyModuleGetter(this, "Heritage",
-    "resource:///modules/devtools/ViewHelpers.jsm");
-
-let Telemetry = devtools.require("devtools/shared/telemetry");
+loader.lazyGetter(this, "promise", () => require("sdk/core/promise"));
+loader.lazyGetter(this, "Telemetry", () => require("devtools/shared/telemetry"));
+loader.lazyGetter(this, "WebConsoleFrame", () => require("devtools/webconsole/webconsole").WebConsoleFrame);
+loader.lazyImporter(this, "gDevTools", "resource:///modules/devtools/gDevTools.jsm");
+loader.lazyImporter(this, "devtools", "resource://gre/modules/devtools/Loader.jsm");
+loader.lazyImporter(this, "Services", "resource://gre/modules/Services.jsm");
+loader.lazyImporter(this, "DebuggerServer", "resource://gre/modules/devtools/dbg-server.jsm");
+loader.lazyImporter(this, "DebuggerClient", "resource://gre/modules/devtools/dbg-client.jsm");
 
 const STRINGS_URI = "chrome://browser/locale/devtools/webconsole.properties";
 let l10n = new WebConsoleUtils.l10n(STRINGS_URI);
 
 const BROWSER_CONSOLE_WINDOW_FEATURES = "chrome,titlebar,toolbar,centerscreen,resizable,dialog=no";
 
 // The preference prefix for all of the Browser Console filters.
 const BROWSER_CONSOLE_FILTER_PREFS_PREFIX = "devtools.browserconsole.filter.";
 
-this.EXPORTED_SYMBOLS = ["HUDService"];
-
 ///////////////////////////////////////////////////////////////////////////
 //// The HUD service
 
 function HUD_SERVICE()
 {
-  this.hudReferences = {};
+  this.consoles = new Map();
+  this.lastFinishedRequest = { callback: null };
 }
 
 HUD_SERVICE.prototype =
 {
+  _browserConsoleID: null,
+  _browserConsoleDefer: null,
+
   /**
-   * Keeps a reference for each HeadsUpDisplay that is created
-   * @type object
+   * Keeps a reference for each Web Console / Browser Console that is created.
+   * @type Map
    */
-  hudReferences: null,
+  consoles: null,
 
   /**
-   * getter for UI commands to be used by the frontend
+   * Assign a function to this property to listen for every request that
+   * completes. Used by unit tests. The callback takes one argument: the HTTP
+   * activity object as received from the remote Web Console.
    *
-   * @returns object
+   * @type object
+   *       Includes a property named |callback|. Assign the function to the
+   *       |callback| property of this object.
    */
-  get consoleUI() {
-    return HeadsUpDisplayUICommands;
-  },
+  lastFinishedRequest: null,
 
   /**
    * Firefox-specific current tab getter
    *
    * @returns nsIDOMWindow
    */
   currentContext: function HS_currentContext() {
     return Services.wm.getMostRecentWindow("navigator:browser");
@@ -95,91 +81,206 @@ HUD_SERVICE.prototype =
    *        The window of the web console owner.
    * @return object
    *         A promise object for the opening of the new WebConsole instance.
    */
   openWebConsole:
   function HS_openWebConsole(aTarget, aIframeWindow, aChromeWindow)
   {
     let hud = new WebConsole(aTarget, aIframeWindow, aChromeWindow);
-    this.hudReferences[hud.hudId] = hud;
+    this.consoles.set(hud.hudId, hud);
     return hud.init();
   },
 
   /**
    * Open a Browser Console for the given target.
    *
-   * @see devtools/framework/Target.jsm for details about targets.
+   * @see devtools/framework/target.js for details about targets.
    *
    * @param object aTarget
    *        The target that the browser console will connect to.
    * @param nsIDOMWindow aIframeWindow
    *        The window where the browser console UI is already loaded.
    * @param nsIDOMWindow aChromeWindow
    *        The window of the browser console owner.
    * @return object
    *         A promise object for the opening of the new BrowserConsole instance.
    */
   openBrowserConsole:
   function HS_openBrowserConsole(aTarget, aIframeWindow, aChromeWindow)
   {
     let hud = new BrowserConsole(aTarget, aIframeWindow, aChromeWindow);
-    this.hudReferences[hud.hudId] = hud;
+    this.consoles.set(hud.hudId, hud);
     return hud.init();
   },
 
   /**
-   * Returns the HeadsUpDisplay object associated to a content window.
+   * Returns the Web Console object associated to a content window.
    *
    * @param nsIDOMWindow aContentWindow
    * @returns object
    */
   getHudByWindow: function HS_getHudByWindow(aContentWindow)
   {
-    for each (let hud in this.hudReferences) {
+    for (let [hudId, hud] of this.consoles) {
       let target = hud.target;
       if (target && target.tab && target.window === aContentWindow) {
         return hud;
       }
     }
     return null;
   },
 
   /**
-   * Returns the hudId that is corresponding to the hud activated for the
-   * passed aContentWindow. If there is no matching hudId null is returned.
-   *
-   * @param nsIDOMWindow aContentWindow
-   * @returns string or null
-   */
-  getHudIdByWindow: function HS_getHudIdByWindow(aContentWindow)
-  {
-    let hud = this.getHudByWindow(aContentWindow);
-    return hud ? hud.hudId : null;
-  },
-
-  /**
-   * Returns the hudReference for a given id.
+   * Returns the console instance for a given id.
    *
    * @param string aId
    * @returns Object
    */
   getHudReferenceById: function HS_getHudReferenceById(aId)
   {
-    return aId in this.hudReferences ? this.hudReferences[aId] : null;
+    return this.consoles.get(aId);
+  },
+
+  /**
+   * Toggle the Web Console for the current tab.
+   *
+   * @return object
+   *         A promise for either the opening of the toolbox that holds the Web
+   *         Console, or a Promise for the closing of the toolbox.
+   */
+  toggleWebConsole: function HS_toggleWebConsole()
+  {
+    let window = this.currentContext();
+    let target = devtools.TargetFactory.forTab(window.gBrowser.selectedTab);
+    let toolbox = gDevTools.getToolbox(target);
+
+    return toolbox && toolbox.currentToolId == "webconsole" ?
+        toolbox.destroy() :
+        gDevTools.showToolbox(target, "webconsole");
+  },
+
+  /**
+   * Find if there is a Web Console open for the current tab and return the
+   * instance.
+   * @return object|null
+   *         The WebConsole object or null if the active tab has no open Web
+   *         Console.
+   */
+  getOpenWebConsole: function HS_getOpenWebConsole()
+  {
+    let tab = this.currentContext().gBrowser.selectedTab;
+    if (!tab || !devtools.TargetFactory.isKnownTab(tab)) {
+      return null;
+    }
+    let target = devtools.TargetFactory.forTab(tab);
+    let toolbox = gDevTools.getToolbox(target);
+    let panel = toolbox ? toolbox.getPanel("webconsole") : null;
+    return panel ? panel.hud : null;
   },
 
   /**
-   * Assign a function to this property to listen for every request that
-   * completes. Used by unit tests. The callback takes one argument: the HTTP
-   * activity object as received from the remote Web Console.
+   * Toggle the Browser Console.
+   */
+  toggleBrowserConsole: function HS_toggleBrowserConsole()
+  {
+    if (this._browserConsoleID) {
+      let hud = this.getHudReferenceById(this._browserConsoleID);
+      return hud.destroy();
+    }
+
+    if (this._browserConsoleDefer) {
+      return this._browserConsoleDefer.promise;
+    }
+
+    this._browserConsoleDefer = promise.defer();
+
+    function connect()
+    {
+      let deferred = promise.defer();
+
+      if (!DebuggerServer.initialized) {
+        DebuggerServer.init();
+        DebuggerServer.addBrowserActors();
+      }
+
+      let client = new DebuggerClient(DebuggerServer.connectPipe());
+      client.connect(() =>
+        client.listTabs((aResponse) => {
+          // Add Global Process debugging...
+          let globals = JSON.parse(JSON.stringify(aResponse));
+          delete globals.tabs;
+          delete globals.selected;
+          // ...only if there are appropriate actors (a 'from' property will
+          // always be there).
+          if (Object.keys(globals).length > 1) {
+            deferred.resolve({ form: globals, client: client, chrome: true });
+          } else {
+            deferred.reject("Global console not found!");
+          }
+        }));
+
+      return deferred.promise;
+    }
+
+    let target;
+    function getTarget(aConnection)
+    {
+      let options = {
+        form: aConnection.form,
+        client: aConnection.client,
+        chrome: true,
+      };
+
+      return devtools.TargetFactory.forRemoteTab(options);
+    }
+
+    function openWindow(aTarget)
+    {
+      target = aTarget;
+
+      let deferred = promise.defer();
+
+      let win = Services.ww.openWindow(null, devtools.Tools.webConsole.url, "_blank",
+                                       BROWSER_CONSOLE_WINDOW_FEATURES, null);
+      win.addEventListener("DOMContentLoaded", function onLoad() {
+        win.removeEventListener("DOMContentLoaded", onLoad);
+
+        // Set the correct Browser Console title.
+        let root = win.document.documentElement;
+        root.setAttribute("title", root.getAttribute("browserConsoleTitle"));
+
+        deferred.resolve(win);
+      });
+
+      return deferred.promise;
+    }
+
+    connect().then(getTarget).then(openWindow).then((aWindow) =>
+      this.openBrowserConsole(target, aWindow, aWindow)
+        .then((aBrowserConsole) => {
+          this._browserConsoleID = aBrowserConsole.hudId;
+          this._browserConsoleDefer.resolve(aBrowserConsole);
+          this._browserConsoleDefer = null;
+        }));
+
+    return this._browserConsoleDefer.promise;
+  },
+
+  /**
+   * Get the Browser Console instance, if open.
    *
-   * @type function
+   * @return object|null
+   *         A BrowserConsole instance or null if the Browser Console is not
+   *         open.
    */
-  lastFinishedRequestCallback: null,
+  getBrowserConsole: function HS_getBrowserConsole()
+  {
+    return this.getHudReferenceById(this._browserConsoleID);
+  },
 };
 
 
 /**
  * A WebConsole instance is an interactive console initialized *per target*
  * that displays console log data as well as provides an interactive terminal to
  * manipulate the target's document content.
  *
@@ -204,36 +305,37 @@ function WebConsole(aTarget, aIframeWind
 
   this.browserWindow = this.chromeWindow.top;
 
   let element = this.browserWindow.document.documentElement;
   if (element.getAttribute("windowtype") != "navigator:browser") {
     this.browserWindow = HUDService.currentContext();
   }
 
-  this.ui = new this.iframeWindow.WebConsoleFrame(this);
+  this.ui = new WebConsoleFrame(this);
 }
 
 WebConsole.prototype = {
   iframeWindow: null,
   chromeWindow: null,
   browserWindow: null,
   hudId: null,
   target: null,
   ui: null,
   _browserConsole: false,
   _destroyer: null,
 
   /**
-   * Getter for HUDService.lastFinishedRequestCallback.
+   * Getter for a function to to listen for every request that completes. Used
+   * by unit tests. The callback takes one argument: the HTTP activity object as
+   * received from the remote Web Console.
    *
-   * @see HUDService.lastFinishedRequestCallback
    * @type function
    */
-  get lastFinishedRequestCallback() HUDService.lastFinishedRequestCallback,
+  get lastFinishedRequestCallback() HUDService.lastFinishedRequest.callback,
 
   /**
    * Getter for the xul:popupset that holds any popups we open.
    * @type nsIDOMElement
    */
   get mainPopupSet()
   {
     return this.browserWindow.document.getElementById("mainPopupSet");
@@ -466,17 +568,17 @@ WebConsole.prototype = {
    *         A promise object that is resolved once the Web Console is closed.
    */
   destroy: function WC_destroy()
   {
     if (this._destroyer) {
       return this._destroyer.promise;
     }
 
-    delete HUDService.hudReferences[this.hudId];
+    HUDService.consoles.delete(this.hudId);
 
     this._destroyer = promise.defer();
 
     let popupset = this.mainPopupSet;
     let panels = popupset.querySelectorAll("panel[hudId=" + this.hudId + "]");
     for (let panel of panels) {
       panel.hidePopup();
     }
@@ -587,158 +689,30 @@ BrowserConsole.prototype = Heritage.exte
 
     this._telemetry.toolClosed("browserconsole");
 
     this._bc_destroyer = promise.defer();
 
     let chromeWindow = this.chromeWindow;
     this.$destroy().then(() =>
       this.target.client.close(() => {
-        HeadsUpDisplayUICommands._browserConsoleID = null;
+        HUDService._browserConsoleID = null;
         chromeWindow.close();
         this._bc_destroyer.resolve(null);
       }));
 
     return this._bc_destroyer.promise;
   },
 });
 
-
-//////////////////////////////////////////////////////////////////////////
-// HeadsUpDisplayUICommands
-//////////////////////////////////////////////////////////////////////////
-
-var HeadsUpDisplayUICommands = {
-  _browserConsoleID: null,
-  _browserConsoleDefer: null,
-
-  /**
-   * Toggle the Web Console for the current tab.
-   *
-   * @return object
-   *         A promise for either the opening of the toolbox that holds the Web
-   *         Console, or a promise for the closing of the toolbox.
-   */
-  toggleHUD: function UIC_toggleHUD()
-  {
-    let window = HUDService.currentContext();
-    let target = devtools.TargetFactory.forTab(window.gBrowser.selectedTab);
-    let toolbox = gDevTools.getToolbox(target);
-
-    return toolbox && toolbox.currentToolId == "webconsole" ?
-        toolbox.destroy() :
-        gDevTools.showToolbox(target, "webconsole");
-  },
-
-  /**
-   * Find if there is a Web Console open for the current tab and return the
-   * instance.
-   * @return object|null
-   *         The WebConsole object or null if the active tab has no open Web
-   *         Console.
-   */
-  getOpenHUD: function UIC_getOpenHUD()
-  {
-    let tab = HUDService.currentContext().gBrowser.selectedTab;
-    if (!tab || !devtools.TargetFactory.isKnownTab(tab)) {
-      return null;
-    }
-    let target = devtools.TargetFactory.forTab(tab);
-    let toolbox = gDevTools.getToolbox(target);
-    let panel = toolbox ? toolbox.getPanel("webconsole") : null;
-    return panel ? panel.hud : null;
-  },
-
-  /**
-   * Toggle the Browser Console.
-   */
-  toggleBrowserConsole: function UIC_toggleBrowserConsole()
-  {
-    if (this._browserConsoleID) {
-      let hud = HUDService.getHudReferenceById(this._browserConsoleID);
-      return hud.destroy();
-    }
-
-    if (this._browserConsoleDefer) {
-      return this._browserConsoleDefer.promise;
-    }
-
-    this._browserConsoleDefer = promise.defer();
-
-    function connect()
-    {
-      let deferred = promise.defer();
-
-      if (!DebuggerServer.initialized) {
-        DebuggerServer.init();
-        DebuggerServer.addBrowserActors();
-      }
-
-      let client = new DebuggerClient(DebuggerServer.connectPipe());
-      client.connect(() =>
-        client.listTabs((aResponse) => {
-          // Add Global Process debugging...
-          let globals = JSON.parse(JSON.stringify(aResponse));
-          delete globals.tabs;
-          delete globals.selected;
-          // ...only if there are appropriate actors (a 'from' property will
-          // always be there).
-          if (Object.keys(globals).length > 1) {
-            deferred.resolve({ form: globals, client: client, chrome: true });
-          } else {
-            deferred.reject("Global console not found!");
-          }
-        }));
-
-      return deferred.promise;
-    }
-
-    let target;
-    function getTarget(aConnection)
-    {
-      let options = {
-        form: aConnection.form,
-        client: aConnection.client,
-        chrome: true,
-      };
-
-      return devtools.TargetFactory.forRemoteTab(options);
-    }
-
-    function openWindow(aTarget)
-    {
-      target = aTarget;
-
-      let deferred = promise.defer();
-
-      let win = Services.ww.openWindow(null, devtools.Tools.webConsole.url, "_blank",
-                                       BROWSER_CONSOLE_WINDOW_FEATURES, null);
-      win.addEventListener("DOMContentLoaded", function onLoad() {
-        win.removeEventListener("DOMContentLoaded", onLoad);
-
-        // Set the correct Browser Console title.
-        let root = win.document.documentElement;
-        root.setAttribute("title", root.getAttribute("browserConsoleTitle"));
-
-        deferred.resolve(win);
-      });
-
-      return deferred.promise;
-    }
-
-    connect().then(getTarget).then(openWindow).then((aWindow) =>
-      HUDService.openBrowserConsole(target, aWindow, aWindow)
-        .then((aBrowserConsole) => {
-          this._browserConsoleID = aBrowserConsole.hudId;
-          this._browserConsoleDefer.resolve(aBrowserConsole);
-          this._browserConsoleDefer = null;
-        }));
-
-    return this._browserConsoleDefer.promise;
-  },
-
-  get browserConsole() {
-    return HUDService.getHudReferenceById(this._browserConsoleID);
-  },
-};
-
 const HUDService = new HUD_SERVICE();
 
+(() => {
+  let methods = ["openWebConsole", "openBrowserConsole", "toggleWebConsole",
+                 "toggleBrowserConsole", "getOpenWebConsole",
+                 "getBrowserConsole", "getHudByWindow", "getHudReferenceById"];
+  for (let method of methods) {
+    exports[method] = HUDService[method].bind(HUDService);
+  }
+
+  exports.consoles = HUDService.consoles;
+  exports.lastFinishedRequest = HUDService.lastFinishedRequest;
+})();
--- a/browser/devtools/webconsole/moz.build
+++ b/browser/devtools/webconsole/moz.build
@@ -1,14 +1,7 @@
 # -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
 # vim: set filetype=python:
 # 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/.
 
 TEST_DIRS += ['test']
-
-EXTRA_JS_MODULES += [
-    'HUDService.jsm',
-    'NetworkPanel.jsm',
-    'WebConsolePanel.jsm',
-]
-
rename from browser/devtools/webconsole/NetworkPanel.jsm
rename to browser/devtools/webconsole/network-panel.js
--- a/browser/devtools/webconsole/NetworkPanel.jsm
+++ b/browser/devtools/webconsole/network-panel.js
@@ -1,52 +1,40 @@
 /* -*- Mode: js2; js2-basic-offset: 2; indent-tabs-mode: nil; -*- */
 /* vim: set ft=javascript ts=2 et sw=2 tw=80: */
 /* 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/. */
 
 "use strict";
 
-const Cc = Components.classes;
-const Ci = Components.interfaces;
-const Cu = Components.utils;
-
-Cu.import("resource://gre/modules/XPCOMUtils.jsm");
-
-XPCOMUtils.defineLazyServiceGetter(this, "mimeService", "@mozilla.org/mime;1",
-                                   "nsIMIMEService");
+const {Cc, Ci, Cu} = require("chrome");
 
-XPCOMUtils.defineLazyModuleGetter(this, "NetworkHelper",
-                                  "resource://gre/modules/devtools/NetworkHelper.jsm");
+loader.lazyGetter(this, "NetworkHelper", () => require("devtools/toolkit/webconsole/network-helper"));
+loader.lazyImporter(this, "NetUtil", "resource://gre/modules/NetUtil.jsm");
+loader.lazyServiceGetter(this, "mimeService", "@mozilla.org/mime;1", "nsIMIMEService");
 
-XPCOMUtils.defineLazyModuleGetter(this, "NetUtil",
-                                  "resource://gre/modules/NetUtil.jsm");
-
-XPCOMUtils.defineLazyModuleGetter(this, "WebConsoleUtils",
-                                  "resource://gre/modules/devtools/WebConsoleUtils.jsm");
+let WebConsoleUtils = require("devtools/toolkit/webconsole/utils").Utils;
 
 const STRINGS_URI = "chrome://browser/locale/devtools/webconsole.properties";
 let l10n = new WebConsoleUtils.l10n(STRINGS_URI);
 
-this.EXPORTED_SYMBOLS = ["NetworkPanel"];
 
 /**
  * Creates a new NetworkPanel.
  *
  * @constructor
  * @param nsIDOMNode aParent
  *        Parent node to append the created panel to.
  * @param object aHttpActivity
  *        HttpActivity to display in the panel.
  * @param object aWebConsoleFrame
  *        The parent WebConsoleFrame object that owns this network panel
  *        instance.
  */
-this.NetworkPanel =
 function NetworkPanel(aParent, aHttpActivity, aWebConsoleFrame)
 {
   let doc = aParent.ownerDocument;
   this.httpActivity = aHttpActivity;
   this.webconsole = aWebConsoleFrame;
   this._longStringClick = this._longStringClick.bind(this);
   this._responseBodyFetch = this._responseBodyFetch.bind(this);
   this._requestBodyFetch = this._requestBodyFetch.bind(this);
@@ -103,16 +91,17 @@ function NetworkPanel(aParent, aHttpActi
   let footer = createElement(doc, "hbox", { align: "end" });
   createAndAppendElement(footer, "spacer", { flex: 1 });
 
   createAndAppendElement(footer, "resizer", { dir: "bottomend" });
   this.panel.appendChild(footer);
 
   aParent.appendChild(this.panel);
 }
+exports.NetworkPanel = NetworkPanel;
 
 NetworkPanel.prototype =
 {
   /**
    * The current state of the output.
    */
   _state: 0,
 
rename from browser/devtools/webconsole/WebConsolePanel.jsm
rename to browser/devtools/webconsole/panel.js
--- a/browser/devtools/webconsole/WebConsolePanel.jsm
+++ b/browser/devtools/webconsole/panel.js
@@ -1,37 +1,30 @@
 /* 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/. */
 
 "use strict";
 
-this.EXPORTED_SYMBOLS = [ "WebConsolePanel" ];
-
-const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
-
-Cu.import("resource://gre/modules/XPCOMUtils.jsm");
+const {Cc, Ci, Cu} = require("chrome");
 
-XPCOMUtils.defineLazyModuleGetter(this, "promise",
-    "resource://gre/modules/commonjs/sdk/core/promise.js", "Promise");
-
-XPCOMUtils.defineLazyModuleGetter(this, "HUDService",
-    "resource:///modules/HUDService.jsm");
-
-XPCOMUtils.defineLazyModuleGetter(this, "EventEmitter",
-    "resource:///modules/devtools/shared/event-emitter.js");
+loader.lazyGetter(this, "promise", () => require("sdk/core/promise"));
+loader.lazyGetter(this, "HUDService", () => require("devtools/webconsole/hudservice"));
+loader.lazyGetter(this, "EventEmitter", () => require("devtools/shared/event-emitter"));
 
 /**
  * A DevToolPanel that controls the Web Console.
  */
-function WebConsolePanel(iframeWindow, toolbox) {
+function WebConsolePanel(iframeWindow, toolbox)
+{
   this._frameWindow = iframeWindow;
   this._toolbox = toolbox;
   EventEmitter.decorate(this);
 }
+exports.WebConsolePanel = WebConsolePanel;
 
 WebConsolePanel.prototype = {
   hud: null,
 
   /**
    * Open is effectively an asynchronous constructor.
    *
    * @return object
--- a/browser/devtools/webconsole/test/Makefile.in
+++ b/browser/devtools/webconsole/test/Makefile.in
@@ -12,17 +12,16 @@ include $(DEPTH)/config/autoconf.mk
 
 MOCHITEST_BROWSER_FILES = \
 	browser_webconsole_notifications.js \
 	browser_webconsole_message_node_id.js \
 	browser_webconsole_bug_580030_errors_after_page_reload.js \
 	browser_webconsole_basic_net_logging.js \
 	browser_webconsole_bug_579412_input_focus.js \
 	browser_webconsole_bug_580001_closing_after_completion.js \
-	browser_webconsole_bug_580400_groups.js \
 	browser_webconsole_bug_588730_text_node_insertion.js \
 	browser_webconsole_bug_601667_filter_buttons.js \
 	browser_webconsole_bug_597136_external_script_errors.js \
 	browser_webconsole_bug_597136_network_requests_from_chrome.js \
 	browser_webconsole_completion.js \
 	browser_webconsole_console_logging_api.js \
 	browser_webconsole_change_font_size.js \
 	browser_webconsole_chrome.js \
@@ -140,16 +139,17 @@ MOCHITEST_BROWSER_FILES = \
 	browser_console_clear_on_reload.js \
 	browser_console_keyboard_accessibility.js \
 	browser_console_filters.js \
 	browser_console_dead_objects.js \
 	browser_console_iframe_messages.js \
 	browser_console_variables_view_while_debugging_and_inspecting.js \
 	browser_webconsole_bug_686937_autocomplete_JSTerm_helpers.js \
 	browser_webconsole_cached_autocomplete.js \
+	browser_console_navigation_marker.js \
 	head.js \
 	$(NULL)
 
 ifeq ($(OS_ARCH), Darwin)
 MOCHITEST_BROWSER_FILES += \
 	browser_webconsole_bug_804845_ctrl_key_nav.js \
         $(NULL)
 endif
--- a/browser/devtools/webconsole/test/browser_bug_871156_ctrlw_close_tab.js
+++ b/browser/devtools/webconsole/test/browser_bug_871156_ctrlw_close_tab.js
@@ -5,62 +5,79 @@
 
 // Check that Ctrl-W closes the Browser Console and that Ctrl-W closes the
 // current tab when using the Web Console - bug 871156.
 
 function test()
 {
   const TEST_URI = "data:text/html;charset=utf8,<title>bug871156</title>\n" +
                    "<p>hello world";
+  let firstTab = gBrowser.selectedTab;
+  Services.prefs.setBoolPref("browser.tabs.animate", false);
+
   addTab(TEST_URI);
   browser.addEventListener("load", function onLoad() {
     browser.removeEventListener("load", onLoad, true);
     openConsole(null, consoleOpened);
   }, true);
 
   function consoleOpened(hud)
   {
     ok(hud, "Web Console opened");
 
-    let tabClosed = false, toolboxDestroyed = false;
+    let tabClosed = promise.defer();
+    let toolboxDestroyed = promise.defer();
+    let tabSelected = promise.defer();
+
+    let pageWindow = firstTab.linkedBrowser.contentWindow;
+    let toolbox = gDevTools.getToolbox(hud.target);
 
     gBrowser.tabContainer.addEventListener("TabClose", function onTabClose() {
       gBrowser.tabContainer.removeEventListener("TabClose", onTabClose);
-
-      ok(true, "tab closed");
+      info("tab closed");
+      tabClosed.resolve(null);
+    });
 
-      tabClosed = true;
-      if (toolboxDestroyed) {
-        testBrowserConsole();
+    gBrowser.tabContainer.addEventListener("TabSelect", function onTabSelect() {
+      gBrowser.tabContainer.removeEventListener("TabSelect", onTabSelect);
+      if (gBrowser.selectedTab == firstTab) {
+        info("tab selected");
+        tabSelected.resolve(null);
       }
     });
 
-    let toolbox = gDevTools.getToolbox(hud.target);
     toolbox.once("destroyed", () => {
-      ok(true, "toolbox destroyed");
-
-      toolboxDestroyed = true;
-      if (tabClosed) {
-        testBrowserConsole();
-      }
+      info("toolbox destroyed");
+      toolboxDestroyed.resolve(null);
     });
 
-    EventUtils.synthesizeKey("w", { accelKey: true }, hud.iframeWindow);
+    promise.all([tabClosed.promise, toolboxDestroyed.promise, tabSelected.promise ]).then(() => {
+      info("promise.all resolved");
+      waitForFocus(testBrowserConsole, pageWindow, true);
+    });
+
+    // Get out of the web console initialization.
+    executeSoon(() => {
+      EventUtils.synthesizeKey("w", { accelKey: true });
+    });
   }
 
   function testBrowserConsole()
   {
     info("test the Browser Console");
 
-    HUDConsoleUI.toggleBrowserConsole().then((hud) => {
+    HUDService.toggleBrowserConsole().then((hud) => {
       ok(hud, "Browser Console opened");
 
       Services.obs.addObserver(function onDestroy() {
         Services.obs.removeObserver(onDestroy, "web-console-destroyed");
         ok(true, "the Browser Console closed");
 
-        executeSoon(finishTest);
+        Services.prefs.clearUserPref("browser.tabs.animate");
+        waitForFocus(finish, content, true);
       }, "web-console-destroyed", false);
 
-      EventUtils.synthesizeKey("w", { accelKey: true }, hud.iframeWindow);
+      waitForFocus(() => {
+        EventUtils.synthesizeKey("w", { accelKey: true }, hud.iframeWindow);
+      }, hud.iframeWindow);
     });
   }
 }
--- a/browser/devtools/webconsole/test/browser_console.js
+++ b/browser/devtools/webconsole/test/browser_console.js
@@ -4,26 +4,31 @@
  */
 
 // Test the basic features of the Browser Console, bug 587757.
 
 const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-console.html?" + Date.now();
 
 function test()
 {
-  let oldFunction = HUDConsoleUI.toggleBrowserConsole;
-  let functionExecuted = false;
-  HUDConsoleUI.toggleBrowserConsole = () => functionExecuted = true;
-  EventUtils.synthesizeKey("j", { accelKey: true, shiftKey: true }, content);
+  Services.obs.addObserver(function observer(aSubject) {
+    Services.obs.removeObserver(observer, "web-console-created");
+    aSubject.QueryInterface(Ci.nsISupportsString);
+
+    let hud = HUDService.getBrowserConsole();
+    ok(hud, "browser console is open");
+    is(aSubject.data, hud.hudId, "notification hudId is correct");
 
-  ok(functionExecuted,
-     "toggleBrowserConsole() was executed by the Ctrl-Shift-J key shortcut");
+    executeSoon(() => consoleOpened(hud));
+  }, "web-console-created", false);
 
-  HUDConsoleUI.toggleBrowserConsole = oldFunction;
-  HUDConsoleUI.toggleBrowserConsole().then(consoleOpened);
+  let hud = HUDService.getBrowserConsole();
+  ok(!hud, "browser console is not open");
+  info("wait for the browser console to open with ctrl-shift-j");
+  EventUtils.synthesizeKey("j", { accelKey: true, shiftKey: true }, content);
 }
 
 function consoleOpened(hud)
 {
   hud.jsterm.clearOutput(true);
 
   expectUncaughtException();
   executeSoon(() => {
--- a/browser/devtools/webconsole/test/browser_console_addonsdk_loader_exception.js
+++ b/browser/devtools/webconsole/test/browser_console_addonsdk_loader_exception.js
@@ -19,17 +19,17 @@ function test()
 
     openConsole(null, consoleOpened);
   }, true);
 
   function consoleOpened(hud)
   {
     ok(hud, "web console opened");
     webconsole = hud;
-    HUDConsoleUI.toggleBrowserConsole().then(browserConsoleOpened);
+    HUDService.toggleBrowserConsole().then(browserConsoleOpened);
   }
 
   function browserConsoleOpened(hud)
   {
     ok(hud, "browser console opened");
     browserconsole = hud;
 
     // Cause an exception in a script loaded with the addon-sdk loader.
--- a/browser/devtools/webconsole/test/browser_console_consolejsm_output.js
+++ b/browser/devtools/webconsole/test/browser_console_consolejsm_output.js
@@ -8,17 +8,17 @@
 function test()
 {
   let storage = Cu.import("resource://gre/modules/ConsoleAPIStorage.jsm", {}).ConsoleAPIStorage;
   storage.clearEvents();
 
   let console = Cu.import("resource://gre/modules/devtools/Console.jsm", {}).console;
   console.log("bug861338-log-cached");
 
-  HUDConsoleUI.toggleBrowserConsole().then(consoleOpened);
+  HUDService.toggleBrowserConsole().then(consoleOpened);
   let hud = null;
 
   function consoleOpened(aHud)
   {
     hud = aHud;
     waitForMessages({
       webconsole: hud,
       messages: [{
--- a/browser/devtools/webconsole/test/browser_console_dead_objects.js
+++ b/browser/devtools/webconsole/test/browser_console_dead_objects.js
@@ -10,17 +10,17 @@ const TEST_URI = "data:text/html;charset
 function test()
 {
   let hud = null;
 
   addTab(TEST_URI);
   browser.addEventListener("load", function onLoad() {
     browser.removeEventListener("load", onLoad, true);
     info("open the browser console");
-    HUDConsoleUI.toggleBrowserConsole().then(onBrowserConsoleOpen);
+    HUDService.toggleBrowserConsole().then(onBrowserConsoleOpen);
   }, true);
 
   function onBrowserConsoleOpen(aHud)
   {
     hud = aHud;
     ok(hud, "browser console opened");
 
     hud.jsterm.clearOutput();
--- a/browser/devtools/webconsole/test/browser_console_error_source_click.js
+++ b/browser/devtools/webconsole/test/browser_console_error_source_click.js
@@ -11,17 +11,17 @@ const TEST_URI = "data:text/html;charset
                  "style='test-color: green-please'>click!</button>";
 function test()
 {
   let hud;
 
   addTab(TEST_URI);
   browser.addEventListener("load", function onLoad() {
     browser.removeEventListener("load", onLoad, true);
-    HUDConsoleUI.toggleBrowserConsole().then(browserConsoleOpened);
+    HUDService.toggleBrowserConsole().then(browserConsoleOpened);
   }, true);
 
   function browserConsoleOpened(aHud)
   {
     hud = aHud;
     ok(hud, "browser console opened");
 
     let button = content.document.querySelector("button");
--- a/browser/devtools/webconsole/test/browser_console_filters.js
+++ b/browser/devtools/webconsole/test/browser_console_filters.js
@@ -40,17 +40,17 @@ function consoleOpened(hud)
   hud.setFilterState("exception", true);
 
   executeSoon(() => closeConsole(null, onWebConsoleClose));
 }
 
 function onWebConsoleClose()
 {
   info("web console closed");
-  HUDConsoleUI.toggleBrowserConsole().then(onBrowserConsoleOpen);
+  HUDService.toggleBrowserConsole().then(onBrowserConsoleOpen);
 }
 
 function onBrowserConsoleOpen(hud)
 {
   ok(hud, "browser console opened");
 
   is(Services.prefs.getBoolPref(BROWSER_CONSOLE_PREFIX + "exception"), true,
      "'exception' filter is enabled (browser console)");
--- a/browser/devtools/webconsole/test/browser_console_iframe_messages.js
+++ b/browser/devtools/webconsole/test/browser_console_iframe_messages.js
@@ -80,17 +80,17 @@ function consoleOpened(hud)
       closeConsole(null, onWebConsoleClose);
     });
   });
 }
 
 function onWebConsoleClose()
 {
   info("web console closed");
-  HUDConsoleUI.toggleBrowserConsole().then(onBrowserConsoleOpen);
+  HUDService.toggleBrowserConsole().then(onBrowserConsoleOpen);
 }
 
 function onBrowserConsoleOpen(hud)
 {
   ok(hud, "browser console opened");
   waitForMessages({
     webconsole: hud,
     messages: expectedMessages,
--- a/browser/devtools/webconsole/test/browser_console_keyboard_accessibility.js
+++ b/browser/devtools/webconsole/test/browser_console_keyboard_accessibility.js
@@ -49,21 +49,24 @@ function test()
     info("try ctrl-f to focus filter");
     EventUtils.synthesizeKey("F", { accelKey: true });
     ok(!hud.jsterm.inputNode.getAttribute("focused"),
        "jsterm input is not focused");
     is(hud.ui.filterBox.getAttribute("focused"), "true",
        "filter input is focused");
 
     if (Services.appinfo.OS == "Darwin") {
+      ok(hud.ui.getFilterState("network"), "network category is enabled");
       EventUtils.synthesizeKey("t", { ctrlKey: true });
+      ok(!hud.ui.getFilterState("network"), "accesskey for Network works");
+      EventUtils.synthesizeKey("t", { ctrlKey: true });
+      ok(hud.ui.getFilterState("network"), "accesskey for Network works (again)");
     }
     else {
       EventUtils.synthesizeKey("N", { altKey: true });
+      let net = hud.ui.document.querySelector("toolbarbutton[category=net]");
+      is(hud.ui.document.activeElement, net,
+         "accesskey for Network category focuses the Net button");
     }
 
-    let net = hud.ui.document.querySelector("toolbarbutton[category=net]");
-    is(hud.ui.document.activeElement, net,
-       "accesskey for Network category focuses the Net button");
-
     finishTest();
   }
 }
new file mode 100644
--- /dev/null
+++ b/browser/devtools/webconsole/test/browser_console_navigation_marker.js
@@ -0,0 +1,81 @@
+/*
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+// Check that the navigation marker shows on page reload - bug 793996.
+
+function test()
+{
+  const PREF = "devtools.webconsole.persistlog";
+  const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-console.html";
+  let hud = null;
+  let Messages = require("devtools/webconsole/console-output").Messages;
+
+  Services.prefs.setBoolPref(PREF, true);
+  registerCleanupFunction(() => Services.prefs.clearUserPref(PREF));
+
+  addTab(TEST_URI);
+
+  browser.addEventListener("load", function onLoad() {
+    browser.removeEventListener("load", onLoad, true);
+    openConsole(null, consoleOpened);
+  }, true);
+
+  function consoleOpened(aHud)
+  {
+    hud = aHud;
+    ok(hud, "Web Console opened");
+
+    hud.jsterm.clearOutput();
+    content.console.log("foobarz1");
+    waitForMessages({
+      webconsole: hud,
+      messages: [{
+        text: "foobarz1",
+        category: CATEGORY_WEBDEV,
+        severity: SEVERITY_LOG,
+      }],
+    }).then(onConsoleMessage);
+  }
+
+  function onConsoleMessage()
+  {
+    browser.addEventListener("load", onReload, true);
+    content.location.reload();
+  }
+
+  function onReload()
+  {
+    browser.removeEventListener("load", onReload, true);
+
+    content.console.log("foobarz2");
+
+    waitForMessages({
+      webconsole: hud,
+      messages: [{
+        name: "page reload",
+        text: "test-console.html",
+        category: CATEGORY_NETWORK,
+        severity: SEVERITY_LOG,
+      },
+      {
+        text: "foobarz2",
+        category: CATEGORY_WEBDEV,
+        severity: SEVERITY_LOG,
+      },
+      {
+        name: "navigation marker",
+        text: "test-console.html",
+        type: Messages.NavigationMarker,
+      }],
+    }).then(onConsoleMessageAfterReload);
+  }
+
+  function onConsoleMessageAfterReload()
+  {
+    isnot(hud.outputNode.textContent.indexOf("foobarz1"), -1,
+          "foobarz1 is still in the output");
+    finishTest();
+  }
+}
--- a/browser/devtools/webconsole/test/browser_console_nsiconsolemessage.js
+++ b/browser/devtools/webconsole/test/browser_console_nsiconsolemessage.js
@@ -46,17 +46,17 @@ function consoleOpened(hud)
        "nsIConsoleMessages are not displayed (confirmed)");
     closeConsole(null, onWebConsoleClose);
   });
 }
 
 function onWebConsoleClose()
 {
   info("web console closed");
-  HUDConsoleUI.toggleBrowserConsole().then(onBrowserConsoleOpen);
+  HUDService.toggleBrowserConsole().then(onBrowserConsoleOpen);
 }
 
 function onBrowserConsoleOpen(hud)
 {
   ok(hud, "browser console opened");
   Services.console.logStringMessage("test2 for bug859756");
 
   waitForMessages({
--- a/browser/devtools/webconsole/test/browser_console_private_browsing.js
+++ b/browser/devtools/webconsole/test/browser_console_private_browsing.js
@@ -123,17 +123,17 @@ function test()
     }).then(testBrowserConsole);
   }
 
   function testBrowserConsole()
   {
     info("testBrowserConsole()");
     closeConsole(privateTab, () => {
       info("web console closed");
-      privateWindow.HUDConsoleUI.toggleBrowserConsole().then(onBrowserConsoleOpen);
+      privateWindow.HUDService.toggleBrowserConsole().then(onBrowserConsoleOpen);
     });
   }
 
   // Make sure that the cached messages from private tabs are not displayed in
   // the browser console.
   function checkNoPrivateMessages()
   {
     let text = hud.outputNode.textContent;
@@ -162,20 +162,20 @@ function test()
   {
     info("close the private window and check if the private messages are removed");
     hud.jsterm.once("private-messages-cleared", () => {
       isnot(hud.outputNode.textContent.indexOf("bug874061-not-private"), -1,
             "non-private messages are still shown after private window closed");
       checkNoPrivateMessages();
 
       info("close the browser console");
-      privateWindow.HUDConsoleUI.toggleBrowserConsole().then(() => {
+      privateWindow.HUDService.toggleBrowserConsole().then(() => {
         info("reopen the browser console");
         executeSoon(() =>
-          HUDConsoleUI.toggleBrowserConsole().then(onBrowserConsoleReopen));
+          HUDService.toggleBrowserConsole().then(onBrowserConsoleReopen));
       });
     });
     privateWindow.BrowserTryToCloseWindow();
   }
 
   function onBrowserConsoleReopen(aHud)
   {
     hud = aHud;
deleted file mode 100644
--- a/browser/devtools/webconsole/test/browser_webconsole_bug_580400_groups.js
+++ /dev/null
@@ -1,78 +0,0 @@
-/* vim:set ts=2 sw=2 sts=2 et: */
-/* 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/. */
-
-// Tests that console groups behave properly.
-
-const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-console.html";
-
-function test() {
-  addTab(TEST_URI);
-  browser.addEventListener("load", function onLoad() {
-    browser.removeEventListener("load", onLoad, true);
-    openConsole(null, testGroups);
-  }, true);
-}
-
-function testGroups(HUD) {
-  let jsterm = HUD.jsterm;
-  let outputNode = HUD.outputNode;
-  jsterm.clearOutput();
-
-  // We test for one group by testing for zero "new" groups. The
-  // "webconsole-new-group" class creates a divider. Thus one group is
-  // indicated by zero new groups, two groups are indicated by one new group,
-  // and so on.
-
-  let waitForSecondMessage = {
-    name: "second console message",
-    validatorFn: function()
-    {
-      return outputNode.querySelectorAll(".webconsole-msg-output").length == 2;
-    },
-    successFn: function()
-    {
-      let timestamp1 = Date.now();
-      if (timestamp1 - timestamp0 < 5000) {
-        is(outputNode.querySelectorAll(".webconsole-new-group").length, 0,
-           "no group dividers exist after the second console message");
-      }
-
-      for (let i = 0; i < outputNode.itemCount; i++) {
-        outputNode.getItemAtIndex(i).timestamp = 0;   // a "far past" value
-      }
-
-      jsterm.execute("2");
-      waitForSuccess(waitForThirdMessage);
-    },
-    failureFn: finishTest,
-  };
-
-  let waitForThirdMessage = {
-    name: "one group divider exists after the third console message",
-    validatorFn: function()
-    {
-      return outputNode.querySelectorAll(".webconsole-new-group").length == 1;
-    },
-    successFn: finishTest,
-    failureFn: finishTest,
-  };
-
-  let timestamp0 = Date.now();
-  jsterm.execute("0");
-
-  waitForSuccess({
-    name: "no group dividers exist after the first console message",
-    validatorFn: function()
-    {
-      return outputNode.querySelectorAll(".webconsole-new-group").length == 0;
-    },
-    successFn: function()
-    {
-      jsterm.execute("1");
-      waitForSuccess(waitForSecondMessage);
-    },
-    failureFn: finishTest,
-  });
-}
--- a/browser/devtools/webconsole/test/browser_webconsole_bug_585956_console_trace.js
+++ b/browser/devtools/webconsole/test/browser_webconsole_bug_585956_console_trace.js
@@ -1,50 +1,49 @@
 /* vim:set ts=2 sw=2 sts=2 et: */
 /* 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/. */
 
 const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-bug-585956-console-trace.html";
 
 function test() {
-  addTab(TEST_URI);
+  addTab("data:text/html;charset=utf8,<p>hello");
   browser.addEventListener("load", tabLoaded, true);
-}
 
-function tabLoaded() {
-  browser.removeEventListener("load", tabLoaded, true);
+  function tabLoaded() {
+    browser.removeEventListener("load", tabLoaded, true);
 
-  openConsole(null, function(hud) {
-    content.location.reload();
+    openConsole(null, function(hud) {
+      content.location = TEST_URI;
 
-    waitForSuccess({
-      name: "stacktrace message",
-      validatorFn: function()
-      {
-        return hud.outputNode.querySelector(".hud-log");
-      },
-      successFn: performChecks,
-      failureFn: finishTest,
+      waitForMessages({
+        webconsole: hud,
+        messages: [{
+          name: "console.trace output",
+          consoleTrace: {
+            file: "test-bug-585956-console-trace.html",
+            fn: "window.foobar585956c",
+          },
+        }],
+      }).then(performChecks);
     });
-  });
+  }
+
+  function performChecks(results) {
+    let node = [...results[0].matched][0];
+
+    // The expected stack trace object.
+    let stacktrace = [
+      { filename: TEST_URI, lineNumber: 9, functionName: "window.foobar585956c", language: 2 },
+      { filename: TEST_URI, lineNumber: 14, functionName: "foobar585956b", language: 2 },
+      { filename: TEST_URI, lineNumber: 18, functionName: "foobar585956a", language: 2 },
+      { filename: TEST_URI, lineNumber: 21, functionName: null, language: 2 }
+    ];
+
+    ok(node, "found trace log node");
+    ok(node._stacktrace, "found stacktrace object");
+    is(node._stacktrace.toSource(), stacktrace.toSource(), "stacktrace is correct");
+    isnot(node.textContent.indexOf("bug-585956"), -1, "found file name");
+
+    finishTest();
+  }
 }
-
-function performChecks() {
-  // The expected stack trace object.
-  let stacktrace = [
-    { filename: TEST_URI, lineNumber: 9, functionName: "window.foobar585956c", language: 2 },
-    { filename: TEST_URI, lineNumber: 14, functionName: "foobar585956b", language: 2 },
-    { filename: TEST_URI, lineNumber: 18, functionName: "foobar585956a", language: 2 },
-    { filename: TEST_URI, lineNumber: 21, functionName: null, language: 2 }
-  ];
-
-  let hudId = HUDService.getHudIdByWindow(content);
-  let HUD = HUDService.hudReferences[hudId];
-
-  let node = HUD.outputNode.querySelector(".hud-log");
-  ok(node, "found trace log node");
-  ok(node._stacktrace, "found stacktrace object");
-  is(node._stacktrace.toSource(), stacktrace.toSource(), "stacktrace is correct");
-  isnot(node.textContent.indexOf("bug-585956"), -1, "found file name");
-
-  finishTest();
-}
--- a/browser/devtools/webconsole/test/browser_webconsole_bug_597756_reopen_closed_tab.js
+++ b/browser/devtools/webconsole/test/browser_webconsole_bug_597756_reopen_closed_tab.js
@@ -20,43 +20,44 @@ function tabLoaded(aEvent) {
     expectUncaughtException();
     content.location.reload();
   });
 }
 
 function tabReloaded(aEvent) {
   gBrowser.selectedBrowser.removeEventListener(aEvent.type, tabReloaded, true);
 
-  let hudId = HUDService.getHudIdByWindow(content);
-  let HUD = HUDService.hudReferences[hudId];
+  let HUD = HUDService.getHudByWindow(content);
   ok(HUD, "Web Console is open");
 
-  waitForSuccess({
-    name: "error message displayed",
-    validatorFn: function() {
-      return HUD.outputNode.textContent.indexOf("fooBug597756_error") > -1;
-    },
-    successFn: function() {
-      if (newTabIsOpen) {
-        finishTest();
-        return;
-      }
-      closeConsole(gBrowser.selectedTab, function() {
-        gBrowser.removeCurrentTab();
+  waitForMessages({
+    webconsole: HUD,
+    messages: [{
+      name: "error message displayed",
+      text: "fooBug597756_error",
+      category: CATEGORY_JS,
+      severity: SEVERITY_ERROR,
+    }],
+  }).then(() => {
+    if (newTabIsOpen) {
+      finishTest();
+      return;
+    }
 
-        let newTab = gBrowser.addTab();
-        gBrowser.selectedTab = newTab;
+    closeConsole(gBrowser.selectedTab, () => {
+      gBrowser.removeCurrentTab();
+
+      let newTab = gBrowser.addTab();
+      gBrowser.selectedTab = newTab;
 
-        newTabIsOpen = true;
-        gBrowser.selectedBrowser.addEventListener("load", tabLoaded, true);
-        expectUncaughtException();
-        content.location = TEST_URI;
-      });
-    },
-    failureFn: finishTest,
+      newTabIsOpen = true;
+      gBrowser.selectedBrowser.addEventListener("load", tabLoaded, true);
+      expectUncaughtException();
+      content.location = TEST_URI;
+    });
   });
 }
 
 function test() {
   expectUncaughtException();
   addTab(TEST_URI);
   browser.addEventListener("load", tabLoaded, true);
 }
--- a/browser/devtools/webconsole/test/browser_webconsole_bug_599725_response_headers.js
+++ b/browser/devtools/webconsole/test/browser_webconsole_bug_599725_response_headers.js
@@ -48,27 +48,27 @@ function performTest(aRequest, aConsole)
                       "response", lastFinishedRequest.response,
                       "updates", lastFinishedRequest.updates,
                       "response headers", headers);
       }
 
       executeSoon(finishTest);
     });
 
-  HUDService.lastFinishedRequestCallback = null;
+  HUDService.lastFinishedRequest.callback = null;
 }
 
 function test()
 {
   addTab("data:text/plain;charset=utf8,hello world");
 
   browser.addEventListener("load", function onLoad() {
     browser.removeEventListener("load", onLoad, true);
     openConsole(null, () => {
-      HUDService.lastFinishedRequestCallback = performTest;
+      HUDService.lastFinishedRequest.callback = performTest;
 
       browser.addEventListener("load", function onReload() {
         browser.removeEventListener("load", onReload, true);
         executeSoon(() => content.location.reload());
       }, true);
 
       executeSoon(() => content.location = TEST_URI);
     });
--- a/browser/devtools/webconsole/test/browser_webconsole_bug_600183_charset.js
+++ b/browser/devtools/webconsole/test/browser_webconsole_bug_600183_charset.js
@@ -8,31 +8,31 @@
  *
  * ***** END LICENSE BLOCK ***** */
 
 const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-bug-600183-charset.html";
 
 function performTest(lastFinishedRequest, aConsole)
 {
   ok(lastFinishedRequest, "charset test page was loaded and logged");
-  HUDService.lastFinishedRequestCallback = null;
+  HUDService.lastFinishedRequest.callback = null;
 
   executeSoon(() => {
     aConsole.webConsoleClient.getResponseContent(lastFinishedRequest.actor,
       (aResponse) => {
         ok(!aResponse.contentDiscarded, "response body was not discarded");
 
         let body = aResponse.content.text;
         ok(body, "we have the response body");
 
         let chars = "\u7684\u95ee\u5019!"; // 的问候!
         isnot(body.indexOf("<p>" + chars + "</p>"), -1,
           "found the chinese simplified string");
 
-        HUDService.lastFinishedRequestCallback = null;
+        HUDService.lastFinishedRequest.callback = null;
         executeSoon(finishTest);
       });
   });
 }
 
 function test()
 {
   addTab("data:text/html;charset=utf-8,Web Console - bug 600183 test");
@@ -40,14 +40,14 @@ function test()
   browser.addEventListener("load", function onLoad() {
     browser.removeEventListener("load", onLoad, true);
 
     openConsole(null, function(hud) {
       hud.ui.setSaveRequestAndResponseBodies(true).then(() => {
         ok(hud.ui._saveRequestAndResponseBodies,
           "The saveRequestAndResponseBodies property was successfully set.");
 
-        HUDService.lastFinishedRequestCallback = performTest;
+        HUDService.lastFinishedRequest.callback = performTest;
         content.location = TEST_URI;
       });
     });
   }, true);
 }
--- a/browser/devtools/webconsole/test/browser_webconsole_bug_601177_log_levels.js
+++ b/browser/devtools/webconsole/test/browser_webconsole_bug_601177_log_levels.js
@@ -5,78 +5,71 @@
  *
  * Contributor(s):
  *  Mihai Șucan <mihai.sucan@gmail.com>
  *
  * ***** END LICENSE BLOCK ***** */
 
 const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-bug-601177-log-levels.html";
 
-function performTest()
-{
-  let hudId = HUDService.getHudIdByWindow(content);
-  let HUD = HUDService.hudReferences[hudId];
-
-  findEntry(HUD, "hud-networkinfo", "test-bug-601177-log-levels.html",
-            "found test-bug-601177-log-levels.html");
-
-  findEntry(HUD, "hud-networkinfo", "test-bug-601177-log-levels.js",
-            "found test-bug-601177-log-levels.js");
-
-  findEntry(HUD, "hud-networkinfo", "test-image.png", "found test-image.png");
-
-  findEntry(HUD, "hud-network", "foobar-known-to-fail.png",
-            "found foobar-known-to-fail.png");
-
-  findEntry(HUD, "hud-exception", "foobarBug601177exception",
-            "found exception");
-
-  findEntry(HUD, "hud-jswarn", "undefinedPropertyBug601177",
-            "found strict warning");
-
-  findEntry(HUD, "hud-jswarn", "foobarBug601177strictError",
-            "found strict error");
-
-  executeSoon(finishTest);
-}
-
-function findEntry(aHUD, aClass, aString, aMessage)
-{
-  return testLogEntry(aHUD.outputNode, aString, aMessage, false, false,
-                      aClass);
-}
-
 function test()
 {
   Services.prefs.setBoolPref("javascript.options.strict", true);
-
   registerCleanupFunction(function() {
     Services.prefs.clearUserPref("javascript.options.strict");
   });
 
   addTab("data:text/html;charset=utf-8,Web Console test for bug 601177: log levels");
 
   browser.addEventListener("load", function onLoad() {
     browser.removeEventListener("load", onLoad, true);
+    openConsole(null, consoleOpened);
+  }, true);
 
-    openConsole(null, function(hud) {
-      browser.addEventListener("load", function onLoad2() {
-        browser.removeEventListener("load", onLoad2, true);
-        waitForSuccess({
-          name: "all messages displayed",
-          validatorFn: function()
-          {
-            return hud.outputNode.itemCount >= 7;
-          },
-          successFn: performTest,
-          failureFn: function() {
-            info("itemCount: " + hud.outputNode.itemCount);
-            finishTest();
-          },
-        });
-      }, true);
+  function consoleOpened(hud)
+  {
+    expectUncaughtException();
+    content.location = TEST_URI;
+
+    info("waiting for messages");
 
-      expectUncaughtException();
-      content.location = TEST_URI;
-    });
-  }, true);
+    waitForMessages({
+      webconsole: hud,
+      messages: [
+        {
+          text: "test-bug-601177-log-levels.html",
+          category: CATEGORY_NETWORK,
+          severity: SEVERITY_LOG,
+        },
+        {
+          text: "test-bug-601177-log-levels.js",
+          category: CATEGORY_NETWORK,
+          severity: SEVERITY_LOG,
+        },
+        {
+          text: "test-image.png",
+          category: CATEGORY_NETWORK,
+          severity: SEVERITY_LOG,
+        },
+        {
+          text: "foobar-known-to-fail.png",
+          category: CATEGORY_NETWORK,
+          severity: SEVERITY_ERROR,
+        },
+        {
+          text: "foobarBug601177exception",
+          category: CATEGORY_JS,
+          severity: SEVERITY_ERROR,
+        },
+        {
+          text: "undefinedPropertyBug601177",
+          category: CATEGORY_JS,
+          severity: SEVERITY_WARNING,
+        },
+        {
+          text: "foobarBug601177strictError",
+          category: CATEGORY_JS,
+          severity: SEVERITY_WARNING,
+        },
+      ],
+    }).then(finishTest);
+  }
 }
-
--- a/browser/devtools/webconsole/test/browser_webconsole_bug_602572_log_bodies_checkbox.js
+++ b/browser/devtools/webconsole/test/browser_webconsole_bug_602572_log_bodies_checkbox.js
@@ -38,18 +38,17 @@ function test()
     }));
   }, true);
 }
 
 function startTest()
 {
   // Find the relevant elements in the Web Console of tab 2.
   let win2 = tabs[runCount*2 + 1].linkedBrowser.contentWindow;
-  let hudId2 = HUDService.getHudIdByWindow(win2);
-  huds[1] = HUDService.hudReferences[hudId2];
+  huds[1] = HUDService.getHudByWindow(win2);
   info("startTest: iframe2 root height " + huds[1].ui.rootElement.clientHeight);
 
   if (runCount == 0) {
     menuitems[1] = huds[1].ui.rootElement.querySelector("#saveBodies");
   }
   else {
     menuitems[1] = huds[1].ui.rootElement.querySelector("#saveBodiesContextMenu");
   }
@@ -96,18 +95,17 @@ function testpopup2b(aEvent) {
 
     info("menupopups[1] hidden");
 
     // Switch to tab 1 and open the Web Console context menu from there.
     gBrowser.selectedTab = tabs[runCount*2];
     waitForFocus(function() {
       // Find the relevant elements in the Web Console of tab 1.
       let win1 = tabs[runCount*2].linkedBrowser.contentWindow;
-      let hudId1 = HUDService.getHudIdByWindow(win1);
-      huds[0] = HUDService.hudReferences[hudId1];
+      huds[0] = HUDService.getHudByWindow(win1);
 
       info("iframe1 root height " + huds[0].ui.rootElement.clientHeight);
 
       menuitems[0] = huds[0].ui.rootElement.querySelector("#saveBodies");
       menupopups[0] = huds[0].ui.rootElement.querySelector("menupopup");
 
       menupopups[0].addEventListener("popupshown", onpopupshown1, false);
       executeSoon(() => menupopups[0].openPopup());
--- a/browser/devtools/webconsole/test/browser_webconsole_bug_618078_network_exceptions.js
+++ b/browser/devtools/webconsole/test/browser_webconsole_bug_618078_network_exceptions.js
@@ -1,70 +1,31 @@
 /* vim:set ts=2 sw=2 sts=2 et: */
 /* 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/. */
 
-// Tests that network log messages bring up the network panel.
+// Tests that we report JS exceptions in event handlers coming from
+// network requests, like onreadystate for XHR. See bug 618078.
 
 const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-bug-618078-network-exceptions.html";
 
-let testEnded = false;
-
-let TestObserver = {
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver]),
-
-  observe: function test_observe(aSubject)
-  {
-    if (testEnded || !(aSubject instanceof Ci.nsIScriptError)) {
-      return;
-    }
-
-    is(aSubject.category, "content javascript", "error category");
-
-    testEnded = true;
-    if (aSubject.category == "content javascript") {
-      executeSoon(checkOutput);
-    }
-    else {
-      executeSoon(finishTest);
-    }
-  }
-};
-
-function checkOutput()
-{
-  waitForSuccess({
-    name: "exception message",
-    validatorFn: function()
-    {
-      return hud.outputNode.textContent.indexOf("bug618078exception") > -1;
-    },
-    successFn: finishTest,
-    failureFn: finishTest,
-  });
-}
-
-function testEnd()
-{
-  Services.console.unregisterListener(TestObserver);
-}
-
 function test()
 {
   addTab("data:text/html;charset=utf-8,Web Console test for bug 618078");
 
   browser.addEventListener("load", function onLoad() {
     browser.removeEventListener("load", onLoad, true);
+    openConsole(null, function(hud) {
+      expectUncaughtException();
+      content.location = TEST_URI;
 
-    openConsole(null, function(aHud) {
-      hud = aHud;
-      Services.console.registerListener(TestObserver);
-      registerCleanupFunction(testEnd);
-
-      executeSoon(function() {
-        expectUncaughtException();
-        content.location = TEST_URI;
-      });
+      waitForMessages({
+        webconsole: hud,
+        messages: [{
+          text: "bug618078exception",
+          category: CATEGORY_JS,
+          severity: SEVERITY_ERROR,
+        }],
+      }).then(finishTest);
     });
   }, true);
 }
-
--- a/browser/devtools/webconsole/test/browser_webconsole_bug_618311_close_panels.js
+++ b/browser/devtools/webconsole/test/browser_webconsole_bug_618311_close_panels.js
@@ -20,38 +20,37 @@ function test() {
           category: CATEGORY_NETWORK,
           severity: SEVERITY_LOG,
         }],
       }).then(performTest);
     });
   }, true);
 }
 
-function performTest() {
-  let hudId = HUDService.getHudIdByWindow(content);
-  let HUD = HUDService.hudReferences[hudId];
+function performTest(results) {
+  let HUD = HUDService.getHudByWindow(content);
 
-  let networkMessage = HUD.outputNode.querySelector(".webconsole-msg-network");
-  ok(networkMessage, "found network message");
+  let networkMessage = [...results[0].matched][0];
+  ok(networkMessage, "network message element");
 
   let networkLink = networkMessage.querySelector(".webconsole-msg-link");
   ok(networkLink, "found network message link");
 
   let popupset = document.getElementById("mainPopupSet");
   ok(popupset, "found #mainPopupSet");
 
   let popupsShown = 0;
   let hiddenPopups = 0;
 
   let onpopupshown = function() {
     document.removeEventListener("popupshown", onpopupshown, false);
     popupsShown++;
 
     executeSoon(function() {
-      let popups = popupset.querySelectorAll("panel[hudId=" + hudId + "]");
+      let popups = popupset.querySelectorAll("panel[hudId=" + HUD.hudId + "]");
       is(popups.length, 1, "found one popup");
 
       document.addEventListener("popuphidden", onpopuphidden, false);
 
       registerCleanupFunction(function() {
         is(hiddenPopups, 1, "correct number of popups hidden");
         if (hiddenPopups != 1) {
           document.removeEventListener("popuphidden", onpopuphidden, false);
@@ -62,17 +61,17 @@ function performTest() {
     });
   };
 
   let onpopuphidden = function() {
     document.removeEventListener("popuphidden", onpopuphidden, false);
     hiddenPopups++;
 
     executeSoon(function() {
-      let popups = popupset.querySelectorAll("panel[hudId=" + hudId + "]");
+      let popups = popupset.querySelectorAll("panel[hudId=" + HUD.hudId + "]");
       is(popups.length, 0, "no popups found");
 
       executeSoon(finishTest);
     });
   };
 
   document.addEventListener("popupshown", onpopupshown, false);
 
--- a/browser/devtools/webconsole/test/browser_webconsole_bug_630733_response_redirect_headers.js
+++ b/browser/devtools/webconsole/test/browser_webconsole_bug_630733_response_redirect_headers.js
@@ -20,17 +20,17 @@ function requestDoneCallback(aHttpReques
 
 function consoleOpened(hud)
 {
   webConsoleClient = hud.ui.webConsoleClient;
   hud.ui.setSaveRequestAndResponseBodies(true).then(() => {
     ok(hud.ui._saveRequestAndResponseBodies,
       "The saveRequestAndResponseBodies property was successfully set.");
 
-    HUDService.lastFinishedRequestCallback = requestDoneCallback;
+    HUDService.lastFinishedRequest.callback = requestDoneCallback;
     waitForSuccess(waitForResponses);
     content.location = TEST_URI;
   });
 
   let waitForResponses = {
     name: "301 and 404 responses",
     validatorFn: function()
     {
@@ -39,17 +39,17 @@ function consoleOpened(hud)
     },
     successFn: getHeaders,
     failureFn: finishTest,
   };
 }
 
 function getHeaders()
 {
-  HUDService.lastFinishedRequestCallback = null;
+  HUDService.lastFinishedRequest.callback = null;
 
   ok("301" in lastFinishedRequests, "request 1: 301 Moved Permanently");
   ok("404" in lastFinishedRequests, "request 2: 404 Not found");
 
   webConsoleClient.getResponseHeaders(lastFinishedRequests["301"].actor,
     function (aResponse) {
       lastFinishedRequests["301"].response.headers = aResponse.headers;
 
--- a/browser/devtools/webconsole/test/browser_webconsole_bug_632347_iterators_generators.js
+++ b/browser/devtools/webconsole/test/browser_webconsole_bug_632347_iterators_generators.js
@@ -9,21 +9,18 @@ function test() {
   addTab(TEST_URI);
   browser.addEventListener("load", function onLoad() {
     browser.removeEventListener("load", onLoad, true);
     openConsole(null, consoleOpened);
   }, true);
 }
 
 function consoleOpened(HUD) {
-  let tmp = {};
-  Cu.import("resource://gre/modules/devtools/WebConsoleUtils.jsm", tmp);
-  let WCU = tmp.WebConsoleUtils;
-  let JSPropertyProvider = tmp.JSPropertyProvider;
-  tmp = null;
+  let tools = Cu.import("resource://gre/modules/devtools/Loader.jsm", {}).devtools;
+  let JSPropertyProvider = tools.require("devtools/toolkit/webconsole/utils").JSPropertyProvider;
 
   let jsterm = HUD.jsterm;
   let win = content.wrappedJSObject;
 
   // Make sure autocomplete does not walk through iterators and generators.
   let result = win.gen1.next();
   let completion = JSPropertyProvider(win, "gen1.");
   is(completion, null, "no matches for gen1");
--- a/browser/devtools/webconsole/test/browser_webconsole_bug_632817.js
+++ b/browser/devtools/webconsole/test/browser_webconsole_bug_632817.js
@@ -23,17 +23,17 @@ function test()
   addTab("data:text/html;charset=utf-8,Web Console network logging tests");
 
   browser.addEventListener("load", function onLoad() {
     browser.removeEventListener("load", onLoad, true);
 
     openConsole(null, function(aHud) {
       hud = aHud;
 
-      HUDService.lastFinishedRequestCallback = function(aRequest) {
+      HUDService.lastFinishedRequest.callback = function(aRequest) {
         lastRequest = aRequest;
         if (requestCallback) {
           requestCallback();
         }
       };
 
       executeSoon(testPageLoad);
     });
@@ -119,22 +119,30 @@ function testFormSubmission()
   // loaded again. Bind to the load event to catch when this is done.
   requestCallback = function() {
     ok(lastRequest, "testFormSubmission() was logged");
     is(lastRequest.request.method, "POST", "Method is correct");
 
     // There should be 3 network requests pointing to the HTML file.
     waitForMessages({
       webconsole: hud,
-      messages: [{
-        text: "test-network-request.html",
-        category: CATEGORY_NETWORK,
-        severity: SEVERITY_LOG,
-        count: 3,
-      }],
+      messages: [
+        {
+          text: "test-network-request.html",
+          category: CATEGORY_NETWORK,
+          severity: SEVERITY_LOG,
+          count: 3,
+        },
+        {
+          text: "test-data.json",
+          category: CATEGORY_NETWORK,
+          severity: SEVERITY_LOG,
+          count: 2,
+        },
+      ],
     }).then(testLiveFilteringOnSearchStrings);
   };
 
   let form = content.document.querySelector("form");
   ok(form, "we have the HTML form");
   form.submit();
 }
 
@@ -165,17 +173,17 @@ function testLiveFilteringOnSearchString
   setStringFilter("'foo'");
   is(countMessageNodes(), 0, "the log nodes are hidden when searching for " +
     "the string 'foo'");
 
   setStringFilter("foo\"bar'baz\"boo'");
   is(countMessageNodes(), 0, "the log nodes are hidden when searching for " +
     "the string \"foo\"bar'baz\"boo'\"");
 
-  HUDService.lastFinishedRequestCallback = null;
+  HUDService.lastFinishedRequest.callback = null;
   lastRequest = null;
   requestCallback = null;
   finishTest();
 }
 
 function countMessageNodes() {
   let messageNodes = hud.outputNode.querySelectorAll(".hud-msg-node");
   let displayedMessageNodes = 0;
--- a/browser/devtools/webconsole/test/browser_webconsole_bug_651501_document_body_autocomplete.js
+++ b/browser/devtools/webconsole/test/browser_webconsole_bug_651501_document_body_autocomplete.js
@@ -17,21 +17,16 @@ function test() {
 let gHUD;
 
 function consoleOpened(aHud) {
   gHUD = aHud;
   let jsterm = gHUD.jsterm;
   let popup = jsterm.autocompletePopup;
   let completeNode = jsterm.completeNode;
 
-  let tmp = {};
-  Cu.import("resource://gre/modules/devtools/WebConsoleUtils.jsm", tmp);
-  let WCU = tmp.WebConsoleUtils;
-  tmp = null;
-
   ok(!popup.isOpen, "popup is not open");
 
   popup._panel.addEventListener("popupshown", function onShown() {
     popup._panel.removeEventListener("popupshown", onShown, false);
 
     ok(popup.isOpen, "popup is open");
 
     // expected properties:
--- a/browser/devtools/webconsole/test/browser_webconsole_bug_653531_highlighter_console_helper.js
+++ b/browser/devtools/webconsole/test/browser_webconsole_bug_653531_highlighter_console_helper.js
@@ -79,56 +79,39 @@ function performTestComparisons()
 
 function performWebConsoleTests(hud)
 {
   let target = TargetFactory.forTab(gBrowser.selectedTab);
   let jsterm = hud.jsterm;
   outputNode = hud.outputNode;
 
   jsterm.clearOutput();
-  jsterm.execute("$0");
+  jsterm.execute("$0", onNodeOutput);
 
-  waitForSuccess({
-    name: "$0 output",
-    validatorFn: function()
-    {
-      return outputNode.querySelector(".webconsole-msg-output");
-    },
-    successFn: function()
-    {
-      let node = outputNode.querySelector(".webconsole-msg-output");
-      isnot(node.textContent.indexOf("[object HTMLHeadingElement"), -1,
-            "correct output for $0");
+  function onNodeOutput()
+  {
+    let node = outputNode.querySelector(".webconsole-msg-output");
+    isnot(node.textContent.indexOf("[object HTMLHeadingElement"), -1,
+          "correct output for $0");
+
+    jsterm.clearOutput();
+    jsterm.execute("$0.textContent = 'bug653531'", onNodeUpdate);
+  }
 
-      jsterm.clearOutput();
-      jsterm.execute("$0.textContent = 'bug653531'");
-      waitForSuccess(waitForNodeUpdate);
-    },
-    failureFn: finishUp,
-  });
+  function onNodeUpdate()
+  {
+    let node = outputNode.querySelector(".webconsole-msg-output");
+    isnot(node.textContent.indexOf("bug653531"), -1,
+          "correct output for $0.textContent");
+    let inspector = gDevTools.getToolbox(target).getPanel("inspector");
+    is(inspector.selection.node.textContent, "bug653531",
+       "node successfully updated");
 
-  let waitForNodeUpdate = {
-    name: "$0.textContent update",
-    validatorFn: function()
-    {
-      return outputNode.querySelector(".webconsole-msg-output");
-    },
-    successFn: function()
-    {
-      let node = outputNode.querySelector(".webconsole-msg-output");
-      isnot(node.textContent.indexOf("bug653531"), -1,
-            "correct output for $0.textContent");
-      let inspector = gDevTools.getToolbox(target).getPanel("inspector");
-      is(inspector.selection.node.textContent, "bug653531",
-         "node successfully updated");
-
-      executeSoon(finishUp);
-    },
-    failureFn: finishUp,
-  };
+    executeSoon(finishUp);
+  }
 }
 
 function finishUp() {
   finishTest();
 }
 
 function test()
 {
--- a/browser/devtools/webconsole/test/browser_webconsole_bug_658368_time_methods.js
+++ b/browser/devtools/webconsole/test/browser_webconsole_bug_658368_time_methods.js
@@ -54,18 +54,17 @@ function testTimerIndependenceInTabs(hud
       executeSoon(testTimerIndependenceInSameTab);
     }, true);
     content.location = "data:text/html;charset=utf-8,<script type='text/javascript'>" +
            "console.time('bTimer');</script>";
   });
 }
 
 function testTimerIndependenceInSameTab() {
-  let hudId = HUDService.getHudIdByWindow(content);
-  let hud = HUDService.hudReferences[hudId];
+  let hud = HUDService.getHudByWindow(content);
   outputNode = hud.outputNode;
 
   waitForSuccess({
     name: "bTimer started",
     validatorFn: function()
     {
       return outputNode.textContent.indexOf("bTimer: timer started") > -1;
     },
@@ -82,18 +81,17 @@ function testTimerIndependenceInSameTab(
         "<script type='text/javascript'>" +
         "console.timeEnd('bTimer');</script>";
     },
     failureFn: finishTest,
   });
 }
 
 function testTimerIndependenceInSameTabAgain() {
-  let hudId = HUDService.getHudIdByWindow(content);
-  let hud = HUDService.hudReferences[hudId];
+  let hud = HUDService.getHudByWindow(content);
   outputNode = hud.outputNode;
 
   executeSoon(function() {
     testLogEntry(outputNode, "bTimer: timer started", "bTimer was not started",
                  false, true);
 
     closeConsole(gBrowser.selectedTab, function() {
       gBrowser.removeCurrentTab();
--- a/browser/devtools/webconsole/test/browser_webconsole_netlogging.js
+++ b/browser/devtools/webconsole/test/browser_webconsole_netlogging.js
@@ -27,17 +27,17 @@ function test()
   addTab("data:text/html;charset=utf-8,Web Console network logging tests");
 
   browser.addEventListener("load", function onLoad() {
     browser.removeEventListener("load", onLoad, true);
 
     openConsole(null, function(aHud) {
       hud = aHud;
 
-      HUDService.lastFinishedRequestCallback = requestCallbackWrapper;
+      HUDService.lastFinishedRequest.callback = requestCallbackWrapper;
 
       executeSoon(testPageLoad);
     });
   }, true);
 }
 
 function requestCallbackWrapper(aRequest)
 {
@@ -199,13 +199,13 @@ function testNetworkPanel()
 
     is(hud.ui.filterBox._netPanel, networkPanel,
        "Network panel stored on anchor node");
     ok(true, "NetworkPanel was opened");
 
     // All tests are done. Shutdown.
     networkPanel.panel.hidePopup();
     lastRequest = null;
-    HUDService.lastFinishedRequestCallback = null;
+    HUDService.lastFinishedRequest.callback = null;
     executeSoon(finishTest);
   }, true);
 }
 
--- a/browser/devtools/webconsole/test/browser_webconsole_notifications.js
+++ b/browser/devtools/webconsole/test/browser_webconsole_notifications.js
@@ -9,24 +9,24 @@ function test() {
   observer.init();
   addTab(TEST_URI);
   browser.addEventListener("load", onLoad, true);
 }
 
 function webConsoleCreated(aID)
 {
   Services.obs.removeObserver(observer, "web-console-created");
-  ok(HUDService.hudReferences[aID], "We have a hud reference");
+  ok(HUDService.getHudReferenceById(aID), "We have a hud reference");
   content.wrappedJSObject.console.log("adding a log message");
 }
 
 function webConsoleDestroyed(aID)
 {
   Services.obs.removeObserver(observer, "web-console-destroyed");
-  ok(!HUDService.hudReferences[aID], "We do not have a hud reference");
+  ok(!HUDService.getHudReferenceById(aID), "We do not have a hud reference");
   executeSoon(finishTest);
 }
 
 function webConsoleMessage(aID, aNodeID)
 {
   Services.obs.removeObserver(observer, "web-console-message-created");
   ok(aID, "we have a console ID");
   is(typeof aNodeID, "string", "message node id is a string");
@@ -38,20 +38,20 @@ let observer = {
   QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver]),
 
   observe: function observe(aSubject, aTopic, aData)
   {
     aSubject = aSubject.QueryInterface(Ci.nsISupportsString);
 
     switch(aTopic) {
       case "web-console-created":
-        webConsoleCreated(aSubject);
+        webConsoleCreated(aSubject.data);
         break;
       case "web-console-destroyed":
-        webConsoleDestroyed(aSubject);
+        webConsoleDestroyed(aSubject.data);
         break;
       case "web-console-message-created":
         webConsoleMessage(aSubject, aData);
         break;
       default:
         break;
     }
   },
--- a/browser/devtools/webconsole/test/browser_webconsole_property_provider.js
+++ b/browser/devtools/webconsole/test/browser_webconsole_property_provider.js
@@ -10,21 +10,18 @@ const TEST_URI = "data:text/html;charset
 
 function test() {
   addTab(TEST_URI);
   browser.addEventListener("load", testPropertyProvider, true);
 }
 
 function testPropertyProvider() {
   browser.removeEventListener("load", testPropertyProvider, true);
-
-  let tmp = {};
-  Cu.import("resource://gre/modules/devtools/WebConsoleUtils.jsm", tmp);
-  let JSPropertyProvider = tmp.JSPropertyProvider;
-  tmp = null;
+  let tools = Cu.import("resource://gre/modules/devtools/Loader.jsm", {}).devtools;
+  let JSPropertyProvider = tools.require("devtools/toolkit/webconsole/utils").JSPropertyProvider;
 
   let completion = JSPropertyProvider(content, "thisIsNotDefined");
   is (completion.matches.length, 0, "no match for 'thisIsNotDefined");
 
   // This is a case the PropertyProvider can't handle. Should return null.
   completion = JSPropertyProvider(content, "window[1].acb");
   is (completion, null, "no match for 'window[1].acb");
 
--- a/browser/devtools/webconsole/test/head.js
+++ b/browser/devtools/webconsole/test/head.js
@@ -1,25 +1,26 @@
 /* vim:set ts=2 sw=2 sts=2 et: */
 /* 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/. */
 
-let tempScope = {};
-Cu.import("resource:///modules/HUDService.jsm", tempScope);
-let HUDService = tempScope.HUDService;
-Cu.import("resource://gre/modules/devtools/WebConsoleUtils.jsm", tempScope);
-let WebConsoleUtils = tempScope.WebConsoleUtils;
-Cu.import("resource:///modules/devtools/gDevTools.jsm", tempScope);
-let gDevTools = tempScope.gDevTools;
-Cu.import("resource://gre/modules/devtools/Loader.jsm", tempScope);
-let TargetFactory = tempScope.devtools.TargetFactory;
-Components.utils.import("resource://gre/modules/devtools/Console.jsm", tempScope);
-let console = tempScope.console;
-let promise = Cu.import("resource://gre/modules/commonjs/sdk/core/promise.js", {}).Promise;
+let WebConsoleUtils, gDevTools, TargetFactory, console, promise, require;
+
+(() => {
+  gDevTools = Cu.import("resource:///modules/devtools/gDevTools.jsm", {}).gDevTools;
+  console = Cu.import("resource://gre/modules/devtools/Console.jsm", {}).console;
+  promise = Cu.import("resource://gre/modules/commonjs/sdk/core/promise.js", {}).Promise;
+
+  let tools = Cu.import("resource://gre/modules/devtools/Loader.jsm", {}).devtools;
+  let utils = tools.require("devtools/toolkit/webconsole/utils");
+  TargetFactory = tools.TargetFactory;
+  WebConsoleUtils = utils.Utils;
+  require = tools.require;
+})();
 // promise._reportErrors = true; // please never leave me.
 
 let gPendingOutputTest = 0;
 
 // The various categories of messages.
 const CATEGORY_NETWORK = 0;
 const CATEGORY_CSS = 1;
 const CATEGORY_JS = 2;
@@ -238,17 +239,17 @@ function waitForContextMenu(aPopup, aBut
 
 /**
  * Dump the output of all open Web Consoles - used only for debugging purposes.
  */
 function dumpConsoles()
 {
   if (gPendingOutputTest) {
     console.log("dumpConsoles start");
-    for each (let hud in HUDService.hudReferences) {
+    for (let hud of HUDService.consoles) {
       if (!hud.outputNode) {
         console.debug("no output content for", hud.hudId);
         continue;
       }
 
       console.debug("output content for", hud.hudId);
       for (let elem of hud.outputNode.childNodes) {
         dumpMessageElement(elem);
@@ -284,24 +285,22 @@ function dumpMessageElement(aMessage)
 }
 
 function finishTest()
 {
   browser = hudId = hud = filterBox = outputNode = cs = null;
 
   dumpConsoles();
 
-  if (HUDConsoleUI.browserConsole) {
-    let hud = HUDConsoleUI.browserConsole;
-
-    if (hud.jsterm) {
-      hud.jsterm.clearOutput(true);
+  let browserConsole = HUDService.getBrowserConsole();
+  if (browserConsole) {
+    if (browserConsole.jsterm) {
+      browserConsole.jsterm.clearOutput(true);
     }
-
-    HUDConsoleUI.toggleBrowserConsole().then(finishTest);
+    HUDService.toggleBrowserConsole().then(finishTest);
     return;
   }
 
   let hud = HUDService.getHudByWindow(content);
   if (!hud) {
     finish();
     return;
   }
@@ -314,18 +313,18 @@ function finishTest()
 
   hud = null;
 }
 
 function tearDown()
 {
   dumpConsoles();
 
-  if (HUDConsoleUI.browserConsole) {
-    HUDConsoleUI.toggleBrowserConsole();
+  if (HUDService.getBrowserConsole()) {
+    HUDService.toggleBrowserConsole();
   }
 
   let target = TargetFactory.forTab(gBrowser.selectedTab);
   gDevTools.closeToolbox(target);
   while (gBrowser.tabs.length > 1) {
     gBrowser.removeCurrentTab();
   }
   WCU_l10n = tab = browser = hudId = hud = filterBox = outputNode = cs = null;
@@ -881,16 +880,19 @@ function getMessageElementText(aElement)
  *            and/or line number in the trace message.
  *            - consoleTime: string that matches a console.time() timer name.
  *            Provide this if you want to match a console.time() message.
  *            - consoleTimeEnd: same as above, but for console.timeEnd().
  *            - consoleDir: boolean, set to |true| to match a console.dir()
  *            message.
  *            - longString: boolean, set to |true} to match long strings in the
  *            message.
+ *            - type: match messages that are instances of the given object. For
+ *            example, you can point to Messages.NavigationMarker to match any
+ *            such message.
  *            - objects: boolean, set to |true| if you expect inspectable
  *            objects in the message.
  *            - source: object that can hold one property: url. This is used to
  *            match the source URL of the message.
  * @return object
  *         A promise object is returned once the messages you want are found.
  *         The promise is resolved with the array of rule objects you give in
  *         the |messages| property. Each objects is the same as provided, with
@@ -1060,18 +1062,35 @@ function waitForMessages(aOptions)
     if (aRule.consoleDir && !checkConsoleDir(aRule, aElement)) {
       return false;
     }
 
     if (aRule.source && !checkSource(aRule, aElement)) {
       return false;
     }
 
+    if (aRule.type) {
+      // The rule tries to match the newer types of messages, based on their
+      // object constructor.
+      if (!aElement._messageObject ||
+          !(aElement._messageObject instanceof aRule.type)) {
+        return false;
+      }
+    }
+    else if (aElement._messageObject) {
+      // If the message element holds a reference to its object, it means this
+      // is a newer message type. All of the older waitForMessages() rules do
+      // not expect this kind of messages. We return false here.
+      // TODO: we keep this behavior until bug 778766 is fixed. After that we
+      // will not require |type| to match newer types of messages.
+      return false;
+    }
+
     let partialMatch = !!(aRule.consoleTrace || aRule.consoleTime ||
-                          aRule.consoleTimeEnd);
+                          aRule.consoleTimeEnd || aRule.type);
 
     if (aRule.category && aElement.category != aRule.category) {
       if (partialMatch) {
         is(aElement.category, aRule.category,
            "message category for rule: " + displayRule(aRule));
         displayErrorContext(aRule, aElement);
       }
       return false;
--- a/browser/devtools/webconsole/webconsole.js
+++ b/browser/devtools/webconsole/webconsole.js
@@ -1,55 +1,39 @@
 /* -*- Mode: js2; js2-basic-offset: 2; indent-tabs-mode: nil; -*- */
 /* vim: set ts=2 et sw=2 tw=80: */
 /* 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/. */
 
 "use strict";
 
-const Cc = Components.classes;
-const Ci = Components.interfaces;
-const Cu = Components.utils;
-
-Cu.import("resource://gre/modules/XPCOMUtils.jsm");
-
-XPCOMUtils.defineLazyModuleGetter(this, "Services",
-                                  "resource://gre/modules/Services.jsm");
-
-XPCOMUtils.defineLazyServiceGetter(this, "clipboardHelper",
-                                   "@mozilla.org/widget/clipboardhelper;1",
-                                   "nsIClipboardHelper");
-
-XPCOMUtils.defineLazyModuleGetter(this, "GripClient",
-                                  "resource://gre/modules/devtools/dbg-client.jsm");
-
-XPCOMUtils.defineLazyModuleGetter(this, "NetworkPanel",
-                                  "resource:///modules/NetworkPanel.jsm");
-
-XPCOMUtils.defineLazyModuleGetter(this, "AutocompletePopup",
-                                  "resource:///modules/devtools/AutocompletePopup.jsm");
-
-XPCOMUtils.defineLazyModuleGetter(this, "WebConsoleUtils",
-                                  "resource://gre/modules/devtools/WebConsoleUtils.jsm");
-
-XPCOMUtils.defineLazyModuleGetter(this, "promise",
-                                  "resource://gre/modules/commonjs/sdk/core/promise.js", "Promise");
-
-XPCOMUtils.defineLazyModuleGetter(this, "VariablesView",
-                                  "resource:///modules/devtools/VariablesView.jsm");
-
-XPCOMUtils.defineLazyModuleGetter(this, "VariablesViewController",
-                                  "resource:///modules/devtools/VariablesViewController.jsm");
-
-XPCOMUtils.defineLazyModuleGetter(this, "EventEmitter",
-                                  "resource:///modules/devtools/shared/event-emitter.js");
-
-XPCOMUtils.defineLazyModuleGetter(this, "devtools",
-                                  "resource://gre/modules/devtools/Loader.jsm");
+const {Cc, Ci, Cu} = require("chrome");
+
+let WebConsoleUtils = require("devtools/toolkit/webconsole/utils").Utils;
+
+loader.lazyServiceGetter(this, "clipboardHelper",
+                         "@mozilla.org/widget/clipboardhelper;1",
+                         "nsIClipboardHelper");
+loader.lazyImporter(this, "Services", "resource://gre/modules/Services.jsm");
+loader.lazyGetter(this, "promise", () => require("sdk/core/promise"));
+loader.lazyGetter(this, "EventEmitter", () => require("devtools/shared/event-emitter"));
+loader.lazyGetter(this, "AutocompletePopup",
+                  () => require("devtools/shared/autocomplete-popup").AutocompletePopup);
+loader.lazyGetter(this, "ToolSidebar",
+                  () => require("devtools/framework/sidebar").ToolSidebar);
+loader.lazyGetter(this, "NetworkPanel",
+                  () => require("devtools/webconsole/network-panel").NetworkPanel);
+loader.lazyGetter(this, "ConsoleOutput",
+                  () => require("devtools/webconsole/console-output").ConsoleOutput);
+loader.lazyGetter(this, "Messages",
+                  () => require("devtools/webconsole/console-output").Messages);
+loader.lazyImporter(this, "GripClient", "resource://gre/modules/devtools/dbg-client.jsm");
+loader.lazyImporter(this, "VariablesView", "resource:///modules/devtools/VariablesView.jsm");
+loader.lazyImporter(this, "VariablesViewController", "resource:///modules/devtools/VariablesViewController.jsm");
 
 const STRINGS_URI = "chrome://browser/locale/devtools/webconsole.properties";
 let l10n = new WebConsoleUtils.l10n(STRINGS_URI);
 
 
 // The XUL namespace.
 const XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
 
@@ -186,43 +170,48 @@ const PREF_PERSISTLOG = "devtools.webcon
 /**
  * A WebConsoleFrame instance is an interactive console initialized *per target*
  * that displays console log data as well as provides an interactive terminal to
  * manipulate the target's document content.
  *
  * The WebConsoleFrame is responsible for the actual Web Console UI
  * implementation.
  *
+ * @constructor
  * @param object aWebConsoleOwner
  *        The WebConsole owner object.
  */
 function WebConsoleFrame(aWebConsoleOwner)
 {
   this.owner = aWebConsoleOwner;
   this.hudId = this.owner.hudId;
+  this.window = this.owner.iframeWindow;
 
   this._repeatNodes = {};
   this._outputQueue = [];
   this._pruneCategoriesQueue = {};
   this._networkRequests = {};
   this.filterPrefs = {};
 
+  this.output = new ConsoleOutput(this);
+
   this._toggleFilter = this._toggleFilter.bind(this);
   this._flushMessageQueue = this._flushMessageQueue.bind(this);
 
   this._outputTimer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
   this._outputTimerInitialized = false;
 
   EventEmitter.decorate(this);
 }
+exports.WebConsoleFrame = WebConsoleFrame;
 
 WebConsoleFrame.prototype = {
   /**
    * The WebConsole instance that owns this frame.
-   * @see HUDService.jsm::WebConsole
+   * @see hudservice.js::WebConsole
    * @type object
    */
   owner: null,
 
   /**
    * Proxy between the Web Console and the remote Web Console instance. This
    * object holds methods used for connecting, listening and disconnecting from
    * the remote server, using the remote debugging protocol.
@@ -337,16 +326,22 @@ WebConsoleFrame.prototype = {
 
   /**
    * The element that holds all of the messages we display.
    * @type nsIDOMElement
    */
   outputNode: null,
 
   /**
+   * The ConsoleOutput instance that manages all output.
+   * @type object
+   */
+  output: null,
+
+  /**
    * The input element that allows the user to filter messages by string.
    * @type nsIDOMElement
    */
   filterBox: null,
 
   /**
    * Getter for the debugger WebConsoleClient.
    * @type object
@@ -466,28 +461,27 @@ WebConsoleFrame.prototype = {
   },
 
   /**
    * Find the Web Console UI elements and setup event listeners as needed.
    * @private
    */
   _initUI: function WCF__initUI()
   {
-    // Remember that this script is loaded in the webconsole.xul context:
-    // |window| is the iframe global.
-    this.window = window;
     this.document = this.window.document;
     this.rootElement = this.document.documentElement;
 
     this._initDefaultFilterPrefs();
 
     // Register the controller to handle "select all" properly.
     this._commandController = new CommandController(this);
     this.window.controllers.insertControllerAt(0, this._commandController);
 
+    this._contextMenuHandler = new ConsoleContextMenu(this);
+
     let doc = this.document;
 
     this.filterBox = doc.querySelector(".hud-filter-box");
     this.outputNode = doc.querySelector(".hud-output-node");
     this.completeNode = doc.querySelector(".jsterm-complete-node");
     this.inputNode = doc.querySelector(".jsterm-input-node");
 
     this._setFilterTextBoxEvents();
@@ -621,16 +615,22 @@ WebConsoleFrame.prototype = {
 
     if (!this.owner._browserConsole) {
       // The Browser Console displays nsIConsoleMessages which are messages that
       // end up in the JS category, but they are not errors or warnings, they
       // are just log messages. The Web Console does not show such messages.
       let jslog = this.document.querySelector("menuitem[prefKey=jslog]");
       jslog.hidden = true;
     }
+
+    if (Services.appinfo.OS == "Darwin") {
+      let net = this.document.querySelector("toolbarbutton[category=net]");
+      let accesskey = net.getAttribute("accesskeyMacOSX");
+      net.setAttribute("accesskey", accesskey);
+    }
   },
 
   /**
    * Increase, decrease or reset the font size.
    *
    * @param string size
    *        The size of the font change. Accepted values are "+" and "-".
    *        An unmatched size assumes a font reset.
@@ -837,18 +837,16 @@ WebConsoleFrame.prototype = {
       let node = result.snapshotItem(i);
       if (aState) {
         node.classList.remove("hud-filtered-by-type");
       }
       else {
         node.classList.add("hud-filtered-by-type");
       }
     }
-
-    this.regroupOutput();
   },
 
   /**
    * Turns the display of log nodes on and off appropriately to reflect the
    * adjustment of the search string.
    */
   adjustVisibilityOnSearchStringChange:
   function WCF_adjustVisibilityOnSearchStringChange()
@@ -865,18 +863,16 @@ WebConsoleFrame.prototype = {
       // if the text matches the words in aSearchString...
       if (this.stringMatchesFilters(text, searchString)) {
         node.classList.remove("hud-filtered-by-string");
       }
       else {
         node.classList.add("hud-filtered-by-string");
       }
     }
-
-    this.regroupOutput();
   },
 
   /**
    * Applies the user's filters to a newly-created message node via CSS
    * classes.
    *
    * @param nsIDOMNode aNode
    *        The newly-created message node.
@@ -1758,16 +1754,45 @@ WebConsoleFrame.prototype = {
   {
     this.contentLocation = aURI;
     if (this.owner.onLocationChange) {
       this.owner.onLocationChange(aURI, aTitle);
     }
   },
 
   /**
+   * Handler for the tabNavigated notification.
+   *
+   * @param string aEvent
+   *        Event name.
+   * @param object aPacket
+   *        Notification packet received from the server.
+   */
+  handleTabNavigated: function WCF_handleTabNavigated(aEvent, aPacket)
+  {
+    if (aEvent == "will-navigate") {
+      if (this.persistLog) {
+        let marker = new Messages.NavigationMarker(aPacket.url, Date.now());
+        this.output.addMessage(marker);
+      }
+      else {
+        this.jsterm.clearOutput();
+      }
+    }
+
+    if (aPacket.url) {
+      this.onLocationChange(aPacket.url, aPacket.title);
+    }
+
+    if (aEvent == "navigate" && !aPacket.nativeConsoleAPI) {
+      this.logWarningAboutReplacedAPI();
+    }
+  },
+
+  /**
    * Output a message node. This filters a node appropriately, then sends it to
    * the output, regrouping and pruning output as necessary.
    *
    * Note: this call is async - the given message node may not be displayed when
    * you call this method.
    *
    * @param integer aCategory
    *        The category of the message you want to output. See the CATEGORY_*
@@ -1870,21 +1895,16 @@ WebConsoleFrame.prototype = {
 
       let categories = Object.keys(this._pruneCategoriesQueue);
       categories.forEach(function _pruneOutput(aCategory) {
         removedNodes += this.pruneOutputIfNecessary(aCategory);
       }, this);
       this._pruneCategoriesQueue = {};
     }
 
-    // Regroup messages at the end of the queue.
-    if (!this._outputQueue.length) {
-      this.regroupOutput();
-    }
-
     let isInputOutput = lastVisibleNode &&
       (lastVisibleNode.classList.contains("webconsole-msg-input") ||
        lastVisibleNode.classList.contains("webconsole-msg-output"));
 
     // Scroll to the new node if it is not filtered, and if the output node is
     // scrolled at the bottom or if the new node is a jsterm input/output
     // message.
     if (lastVisibleNode && (scrolledToBottom || isInputOutput)) {
@@ -2144,39 +2164,16 @@ WebConsoleFrame.prototype = {
     }
 
     if (aNode.parentNode) {
       aNode.parentNode.removeChild(aNode);
     }
   },
 
   /**
-   * Splits the given console messages into groups based on their timestamps.
-   */
-  regroupOutput: function WCF_regroupOutput()
-  {
-    // Go through the nodes and adjust the placement of "webconsole-new-group"
-    // classes.
-    let nodes = this.outputNode.querySelectorAll(".hud-msg-node" +
-      ":not(.hud-filtered-by-string):not(.hud-filtered-by-type)");
-    let lastTimestamp;
-    for (let i = 0, n = nodes.length; i < n; i++) {
-      let thisTimestamp = nodes[i].timestamp;
-      if (lastTimestamp != null &&
-          thisTimestamp >= lastTimestamp + NEW_GROUP_DELAY) {
-        nodes[i].classList.add("webconsole-new-group");
-      }
-      else {
-        nodes[i].classList.remove("webconsole-new-group");
-      }
-      lastTimestamp = thisTimestamp;
-    }
-  },
-
-  /**
    * Given a category and message body, creates a DOM node to represent an
    * incoming message. The timestamp is automatically added.
    *
    * @param number aCategory
    *        The category of the message: one of the CATEGORY_* constants.
    * @param number aSeverity
    *        The severity of the message: one of the SEVERITY_* constants;
    * @param string|nsIDOMNode aBody
@@ -2629,41 +2626,29 @@ WebConsoleFrame.prototype = {
    *        other meta-information. Default is false.
    */
   copySelectedItems: function WCF_copySelectedItems(aOptions)
   {
     aOptions = aOptions || { linkOnly: false };
 
     // Gather up the selected items and concatenate their clipboard text.
     let strings = [];
-    let newGroup = false;
 
     let children = this.outputNode.children;
 
     for (let i = 0; i < children.length; i++) {
       let item = children[i];
       if (!item.selected) {
         continue;
       }
 
-      // Add dashes between groups so that group boundaries show up in the
-      // copied output.
-      if (i > 0 && item.classList.contains("webconsole-new-group")) {
-        newGroup = true;
-      }
-
       // Ensure the selected item hasn't been filtered by type or string.
       if (!item.classList.contains("hud-filtered-by-type") &&
           !item.classList.contains("hud-filtered-by-string")) {
         let timestampString = l10n.timestampString(item.timestamp);
-        if (newGroup) {
-          strings.push("--");
-          newGroup = false;
-        }
-
         if (aOptions.linkOnly) {
           strings.push(item.url);
         }
         else {
           strings.push("[" + timestampString + "] " + item.clipboardText);
         }
       }
     }
@@ -2748,16 +2733,23 @@ WebConsoleFrame.prototype = {
       this._outputTimer.cancel();
     }
     this._outputTimer = null;
 
     if (this.jsterm) {
       this.jsterm.destroy();
       this.jsterm = null;
     }
+    this.output.destroy();
+    this.output = null;
+
+    if (this._contextMenuHandler) {
+      this._contextMenuHandler.destroy();
+      this._contextMenuHandler = null;
+    }
 
     this._commandController = null;
 
     let onDestroy = function() {
       this._destroyer.resolve(null);
     }.bind(this);
 
     if (this.proxy) {
@@ -3283,17 +3275,16 @@ JSTerm.prototype = {
    * Create the Web Console sidebar.
    *
    * @see devtools/framework/sidebar.js
    * @private
    */
   _createSidebar: function JST__createSidebar()
   {
     let tabbox = this.hud.document.querySelector("#webconsole-sidebar");
-    let ToolSidebar = devtools.require("devtools/framework/sidebar").ToolSidebar;
     this.sidebar = new ToolSidebar(tabbox, this, "webconsole");
     this.sidebar.show();
   },
 
   /**
    * Add the variables view tab to the sidebar.
    *
    * @private
@@ -4985,27 +4976,17 @@ WebConsoleConnectionProxy.prototype = {
    *        The message received from the server.
    */
   _onTabNavigated: function WCCP__onTabNavigated(aEvent, aPacket)
   {
     if (!this.owner) {
       return;
     }
 
-    if (aEvent == "will-navigate" && !this.owner.persistLog) {
-      this.owner.jsterm.clearOutput();
-    }
-
-    if (aPacket.url) {
-      this.owner.onLocationChange(aPacket.url, aPacket.title);
-    }
-
-    if (aEvent == "navigate" && !aPacket.nativeConsoleAPI) {
-      this.owner.logWarningAboutReplacedAPI();
-    }
+    this.owner.handleTabNavigated(aEvent, aPacket);
   },
 
   /**
    * Release an object actor.
    *
    * @param string aActor
    *        The actor ID to send the request to.
    */
@@ -5058,50 +5039,45 @@ WebConsoleConnectionProxy.prototype = {
 
 function gSequenceId()
 {
   return gSequenceId.n++;
 }
 gSequenceId.n = 0;
 
 
-function goUpdateConsoleCommands() {
-  goUpdateCommand("consoleCmd_openURL");
-  goUpdateCommand("consoleCmd_copyURL");
-}
-
-
-
 ///////////////////////////////////////////////////////////////////////////////
 // Context Menu
 ///////////////////////////////////////////////////////////////////////////////
 
-const CONTEXTMENU_ID = "output-contextmenu";
-
 /*
- * ConsoleContextMenu: This handle to show/hide a context menu item.
+ * ConsoleContextMenu this used to handle the visibility of context menu items.
+ *
+ * @constructor
+ * @param object aOwner
+ *        The WebConsoleFrame instance that owns this object.
  */
-let ConsoleContextMenu = {
+function ConsoleContextMenu(aOwner)
+{
+  this.owner = aOwner;
+  this.popup = this.owner.document.getElementById("output-contextmenu");
+  this.build = this.build.bind(this);
+  this.popup.addEventListener("popupshowing", this.build);
+}
+
+ConsoleContextMenu.prototype = {
   /*
    * Handle to show/hide context menu item.
-   *
-   * @param nsIDOMEvent aEvent
    */
   build: function CCM_build(aEvent)
   {
-    let popup = aEvent.target;
-    if (popup.id !== CONTEXTMENU_ID) {
-      return;
-    }
-
-    let view = document.querySelector(".hud-output-node");
+    let view = this.owner.outputNode;
     let metadata = this.getSelectionMetadata(view);
 
-    for (let i = 0, l = popup.childNodes.length; i < l; ++i) {
-      let element = popup.childNodes[i];
+    for (let element of this.popup.children) {
       element.hidden = this.shouldHideMenuItem(element, metadata);
     }
   },
 
   /*
    * Get selection information from the view.
    *
    * @param nsIDOMElement aView
@@ -5168,9 +5144,20 @@ let ConsoleContextMenu = {
       if (itemData.indexOf(type) !== -1) {
         shouldHide = false;
         break;
       }
     }
 
     return shouldHide;
   },
+
+  /**
+   * Destroy the ConsoleContextMenu object instance.
+   */
+  destroy: function CCM_destroy()
+  {
+    this.popup.removeEventListener("popupshowing", this.build);
+    this.popup = null;
+    this.owner = null;
+  },
 };
+
--- a/browser/devtools/webconsole/webconsole.xul
+++ b/browser/devtools/webconsole/webconsole.xul
@@ -17,17 +17,22 @@
         macanimationtype="document"
         fullscreenbutton="true"
         title="&window.title;"
         browserConsoleTitle="&browserConsole.title;"
         windowtype="devtools:webconsole"
         width="900" height="350"
         persist="screenX screenY width height sizemode">
   <script type="text/javascript" src="chrome://global/content/globalOverlay.js"/>
-  <script type="text/javascript" src="webconsole.js"/>
+  <script type="text/javascript"><![CDATA[
+function goUpdateConsoleCommands() {
+  goUpdateCommand("consoleCmd_openURL");
+  goUpdateCommand("consoleCmd_copyURL");
+}
+  // ]]></script>
 
   <commandset id="editMenuCommands"/>
 
   <commandset id="consoleCommands"
               commandupdater="true"
               events="richlistbox-select"
               oncommandupdate="goUpdateConsoleCommands();">
     <command id="consoleCmd_openURL"
@@ -52,18 +57,17 @@
     <key key="&fullZoomResetCmd.commandkey2;" command="cmd_fullZoomReset" modifiers="accel"/>
     <key key="&findCmd.key;" command="cmd_find" modifiers="accel"/>
     <key key="&clearOutputCmd.key;" command="consoleCmd_clearOutput" modifiers="accel"/>
     <key key="&closeCmd.key;" command="cmd_close" modifiers="accel"/>
   </keyset>
   <keyset id="editMenuKeys"/>
 
   <popupset id="mainPopupSet">
-    <menupopup id="output-contextmenu"
-               onpopupshowing="ConsoleContextMenu.build(event);">
+    <menupopup id="output-contextmenu">
       <menuitem id="saveBodiesContextMenu" type="checkbox" label="&saveBodies.label;"
                 accesskey="&saveBodies.accesskey;"/>
       <menuitem id="menu_openURL" label="&openURL.label;"
                 accesskey="&openURL.accesskey;" command="consoleCmd_openURL"
                 selection="network" selectionType="single"/>
       <menuitem id="menu_copyURL" label="&copyURLCmd.label;"
                 accesskey="&copyURLCmd.accesskey;" command="consoleCmd_copyURL"
                 selection="network" selectionType="single"/>
@@ -73,21 +77,18 @@
   </popupset>
 
   <box class="hud-outer-wrapper devtools-responsive-container" flex="1">
     <vbox class="hud-console-wrapper" flex="1">
       <toolbar class="hud-console-filter-toolbar devtools-toolbar" mode="full">
         <toolbarbutton label="&btnPageNet.label;" type="menu-button"
                        category="net" class="devtools-toolbarbutton webconsole-filter-button"
                        tooltiptext="&btnPageNet.tooltip;"
-#ifdef XP_MACOSX
-                       accesskey="&btnPageNet.accesskeyMacOSX;"
-#else
+                       accesskeyMacOSX="&btnPageNet.accesskeyMacOSX;"
                        accesskey="&btnPageNet.accesskey;"
-#endif
                        tabindex="3">
           <menupopup>
             <menuitem label="&btnConsoleErrors;" type="checkbox" autocheck="false"
                       prefKey="network"/>
             <menuitem label="&btnConsoleWarnings;" type="checkbox" autocheck="false"
                       prefKey="netwarn"/>
             <menuitem label="&btnConsoleLog;" type="checkbox" autocheck="false"
                       prefKey="networkinfo"/>
--- a/browser/installer/removed-files.in
+++ b/browser/installer/removed-files.in
@@ -1,1554 +1,96 @@
 # 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/.
-# Removed-files.in is processed at build time to create a list of files that
-# should be removed during an application update.
-# These files are in alphabetical order, except that files removed only on
-# certain platforms are after all of the regular files and obsolete Talkback and
-# Inspector files are at the very end.
-.autoreg
-@DLL_PREFIX@jsj@DLL_SUFFIX@
-@DLL_PREFIX@sqlite3@DLL_SUFFIX@
-@DLL_PREFIX@xpcom_compat@DLL_SUFFIX@
-@DLL_PREFIX@xpistub@DLL_SUFFIX@
-@DLL_PREFIX@zlib@DLL_SUFFIX@
-@DLL_PREFIX@jemalloc@DLL_SUFFIX@
-@DLL_PREFIX@mozutils@DLL_SUFFIX@
-#ifdef MOZ_STATIC_JS
-@DLL_PREFIX@mozjs@DLL_SUFFIX@
-#endif
-#ifdef MOZ_FOLD_LIBS
-@DLL_PREFIX@nspr4@DLL_SUFFIX@
-@DLL_PREFIX@plds4@DLL_SUFFIX@
-@DLL_PREFIX@plc4@DLL_SUFFIX@
-@DLL_PREFIX@ssl3@DLL_SUFFIX@
-@DLL_PREFIX@smime3@DLL_SUFFIX@
-@DLL_PREFIX@nssutil3@DLL_SUFFIX@
-@DLL_PREFIX@mozsqlite3@DLL_SUFFIX@
-#endif
-@DLL_PREFIX@xpcom@DLL_SUFFIX@
-LICENSE
-browserconfig.properties
-chrome/US.jar
-chrome/app-chrome.manifest
-chrome/browser.manifest
-chrome/chrome.rdf
-chrome/chromelist.txt
-chrome/classic.jar
-chrome/classic.manifest
-chrome/comm.jar
-chrome/comm.manifest
-chrome/en-win.jar
-chrome/help.jar
-chrome/installed-chrome.txt
-chrome/m3ffxtbr.jar
-chrome/m3ffxtbr.manifest
-chrome/overlayinfo/
-chrome/pippki.manifest
-chrome/reporter.jar
-chrome/reporter.manifest
-chrome/toolkit.manifest
-component.reg
-components/browser.manifest
-components/components.list
-components/@DLL_PREFIX@browserdirprovider@DLL_SUFFIX@
-components/@DLL_PREFIX@brwsrdir@DLL_SUFFIX@
-components/@DLL_PREFIX@myspell@DLL_SUFFIX@
-components/@DLL_PREFIX@spellchecker@DLL_SUFFIX@
-components/@DLL_PREFIX@spellchk@DLL_SUFFIX@
-#ifdef XP_MACOSX
-components/libalerts.dylib
-components/libalerts_s.dylib
+
+# The removed-files.in file specifies files and directories to be removed during
+# an application update that are not automatically removed by the application
+# update process. The application update process handles the vast majority of
+# file and directory removals automatically so this file should not be used in
+# the vast majority of cases.
+
+# When to use removed-files.in file to remove files and directories:
+# * Files and directories located in the installation's "distribution/" and
+#   "extensions/" directories that were added before Firefox 26. Files and
+#   directories located in these directories were not included in the
+#   application update file removals for a complete update prior to Firefox 26.
+# * Empty directories that were accidentally added to the installation
+#   directory.
+# * Third party files and directories that were added to the installation
+#   directory. Under normal circumstances this should only be done after release
+#   drivers have approved the removal of these third party files.
+
+# If you are not sure whether a file or directory should be removed using the
+# removed-files.in file please contact one of the developers that work on
+# application update.
+
+# Note: the "distribution/" and "browser/extensions/" directories should never
+# be removed recursively since these directories are used by Partner builds and
+# custom installations.
+
+# To specify a file to be removed add the path to the file.
+# * If the file doesn't exist the update will succeed.
+# * If the file exists and can't be removed (e.g. the file is locked) the
+#   update will fail.
+#
+# Example: path/to/file
+
+# To specify a directory to be removed only if it is empty add the path to the
+# directory with a trailing forward slash.
+# * If the directory doesn't exist the update will succeed.
+# * If the directory can't be removed (e.g. the directory is locked, contains
+#   files, etc.) the update will succeed.
+#
+# Example: path/to/dir/
+
+# To specify a directory that should be recursively removed add the path to the
+# directory with a trailing forward slash and "*".
+# * If the directory doesn't exist the update will succeed.
+# * If all of the files the directory contains can be removed but the directory
+#   or a subdirectory can't be removed (e.g. the directory is locked) the update
+#   will succeed.
+# * If a file within the directory can't be removed the update will fail.
+#
+# Example: path/to/dir/*
+
+# File Removals
+# This is located under the "distribution/" directory and it was added before
+# Firefox 26
+distribution/extensions/testpilot@labs.mozilla.com.xpi
+
+# Directory removals
+chrome/
+#ifdef XP_UNIX
+  #ifndef XP_MACOSX
+    chrome/icons/
+    chrome/icons/default/
+  #endif
 #endif
-components/aboutCertError.js
-components/aboutPrivateBrowsing.js
-components/aboutRights.js
-components/aboutRobots.js
-components/aboutSessionRestore.js
-components/autocomplete.xpt
-components/airbag.xpt
-components/bookmarks.xpt
-components/compreg.dat
-components/history.xpt
-components/microsummaries.xpt
-components/myspell/en-US.aff
-components/myspell/en-US.dic
-components/nsAddonRepository.js
-components/nsBackgroundUpdateService.js
-components/nsBookmarkTransactionManager.js
-components/nsCloseAllWindows.js
-components/nsDictionary.js
-components/nsExtensionManager.js
-components/nsInterfaceInfoToIDL.js
-components/nsScriptableIO.js
-components/nsUrlClassifierTable.js
-components/nsXmlRpcClient.js
-components/pluginGlue.js
-components/sidebar.xpt
-#ifdef MOZ_B2G_RIL
-components/dom_telephony.xpt
-components/dom_wifi.xpt
-components/dom_system_b2g.xpt
-#endif
-components/dom_sms.xpt
-components/dom_webspeech.xpt
-components/uconvd.dll
-components/WeaveCrypto.js
-components/WeaveCrypto.manifest
-components/xmlextras.xpt
-components/xpcom.xpt
-components/xpti.dat
-components/xptitemp.dat
-components/nsMicrosummaryService.js
-components/nsProxyAutoConfig.manifest
-components/nsProxyAutoConfig.js
-D3DCompiler_42.dll
-d3dx9_42.dll
-d3dx9_43.dll
-defaults/pref/all.js
-defaults/pref/bug259708.js
-defaults/pref/bug307259.js
-defaults/pref/reporter.js
-defaults/pref/security-prefs.js
-defaults/pref/services-aitc.js
-defaults/pref/winpref.js
-defaults/pref/xpinstall.js
-defaults/preferences/services-aitc.js
-defaults/preferences/services-notifications.js
-defaults/preferences/services-sync.js
-defaults/preferences/healthreport-prefs.js
-defaults/profile/US/
+chrome/overlayinfo/
+components/
+defaults/autoconfig/
+defaults/profile/
+defaults/profile/chrome/
+defaults/profile/US/*
 defaults/profile/extensions/
-defaults/profile/extensions/Extensions.rdf
-defaults/profile/extensions/installed-extensions.txt
-defaults/profile/extensions/{972ce4c6-7e08-4474-a285-3208198ce6fd}/
-defaults/profile/extensions/{972ce4c6-7e08-4474-a285-3208198ce6fd}/install.rdf
-defaults/profile/search.rdf
-#ifndef SHIP_FEEDBACK
-# In the average case, this directory is only used by Test Pilot, and will get
-# removed by the updater. In some cases (eg, partner builds), distribution/
-# will have other files and/or directories in it. In these cases, the updater
-# will print a non-fatal error and continue on, because we're not appending
-# '*' to force a recursive removal.
+defaults/profile/extensions/{972ce4c6-7e08-4474-a285-3208198ce6fd}/*
 distribution/
 distribution/extensions/
-distribution/extensions/testpilot@labs.mozilla.com.xpi
-#endif
-extensions/talkback@mozilla.org/
-extensions/talkback@mozilla.org/chrome.manifest
-extensions/talkback@mozilla.org/components/@DLL_PREFIX@qfaservices@DLL_SUFFIX@
-extensions/talkback@mozilla.org/components/qfaservices.xpt
-extensions/talkback@mozilla.org/install.rdf
-extensions/{641d8d09-7dda-4850-8228-ac0ab65e2ac9}/
-extensions/{641d8d09-7dda-4850-8228-ac0ab65e2ac9}/install.rdf
-extensions/{972ce4c6-7e08-4474-a285-3208198ce6fd}/preview.png
-extensions/testpilot@labs.mozilla.com/chrome.manifest
-extensions/testpilot@labs.mozilla.com/components/TestPilot.js
-extensions/testpilot@labs.mozilla.com/content/all-studies-window.js
-extensions/testpilot@labs.mozilla.com/content/all-studies-window.xul
-extensions/testpilot@labs.mozilla.com/content/browser.css
-extensions/testpilot@labs.mozilla.com/content/browser.js
-extensions/testpilot@labs.mozilla.com/content/debug.html
-extensions/testpilot@labs.mozilla.com/content/experiment-page.js
-extensions/testpilot@labs.mozilla.com/content/feedback-browser.xul
-extensions/testpilot@labs.mozilla.com/content/flot/jquery.colorhelpers.js
-extensions/testpilot@labs.mozilla.com/content/flot/jquery.colorhelpers.min.js
-extensions/testpilot@labs.mozilla.com/content/flot/jquery.flot.crosshair.js
-extensions/testpilot@labs.mozilla.com/content/flot/jquery.flot.crosshair.min.js
-extensions/testpilot@labs.mozilla.com/content/flot/jquery.flot.image.js
-extensions/testpilot@labs.mozilla.com/content/flot/jquery.flot.image.min.js
-extensions/testpilot@labs.mozilla.com/content/flot/jquery.flot.js
-extensions/testpilot@labs.mozilla.com/content/flot/jquery.flot.min.js
-extensions/testpilot@labs.mozilla.com/content/flot/jquery.flot.navigate.js
-extensions/testpilot@labs.mozilla.com/content/flot/jquery.flot.navigate.min.js
-extensions/testpilot@labs.mozilla.com/content/flot/jquery.flot.selection.js
-extensions/testpilot@labs.mozilla.com/content/flot/jquery.flot.selection.min.js
-extensions/testpilot@labs.mozilla.com/content/flot/jquery.flot.stack.js
-extensions/testpilot@labs.mozilla.com/content/flot/jquery.flot.stack.min.js
-extensions/testpilot@labs.mozilla.com/content/flot/jquery.flot.threshold.js
-extensions/testpilot@labs.mozilla.com/content/flot/jquery.flot.threshold.min.js
-extensions/testpilot@labs.mozilla.com/content/flot/jquery.js
-extensions/testpilot@labs.mozilla.com/content/flot/jquery.min.js
-extensions/testpilot@labs.mozilla.com/content/raw-data-dialog.js
-extensions/testpilot@labs.mozilla.com/content/raw-data-dialog.xul
-extensions/testpilot@labs.mozilla.com/content/screen.css
-extensions/testpilot@labs.mozilla.com/content/status-quit.html
-extensions/testpilot@labs.mozilla.com/content/status.html
-extensions/testpilot@labs.mozilla.com/content/survey-generator.js
-extensions/testpilot@labs.mozilla.com/content/take-survey.html
-extensions/testpilot@labs.mozilla.com/content/tp-browser.xul
-extensions/testpilot@labs.mozilla.com/content/welcome-page.js
-extensions/testpilot@labs.mozilla.com/content/welcome.html
-extensions/testpilot@labs.mozilla.com/content/window-utils.js
-extensions/testpilot@labs.mozilla.com/defaults/preferences/preferences.js
-extensions/testpilot@labs.mozilla.com/install.rdf
-extensions/testpilot@labs.mozilla.com/instrument/chrome.manifest
-extensions/testpilot@labs.mozilla.com/instrument/install.rdf
-extensions/testpilot@labs.mozilla.com/instrument/instrument.jsm
-extensions/testpilot@labs.mozilla.com/instrument/instrument.xul
-extensions/testpilot@labs.mozilla.com/modules/dbutils.js
-extensions/testpilot@labs.mozilla.com/modules/experiment_data_store.js
-extensions/testpilot@labs.mozilla.com/modules/extension-update.js
-extensions/testpilot@labs.mozilla.com/modules/feedback.js
-extensions/testpilot@labs.mozilla.com/modules/jar-code-store.js
-extensions/testpilot@labs.mozilla.com/modules/lib/cuddlefish.js
-extensions/testpilot@labs.mozilla.com/modules/lib/memory.js
-extensions/testpilot@labs.mozilla.com/modules/lib/observer-service.js
-extensions/testpilot@labs.mozilla.com/modules/lib/plain-text-console.js
-extensions/testpilot@labs.mozilla.com/modules/lib/preferences-service.js
-extensions/testpilot@labs.mozilla.com/modules/lib/securable-module.js
-extensions/testpilot@labs.mozilla.com/modules/lib/timer.js
-extensions/testpilot@labs.mozilla.com/modules/lib/traceback.js
-extensions/testpilot@labs.mozilla.com/modules/lib/unit-test.js
-extensions/testpilot@labs.mozilla.com/modules/lib/unload.js
-extensions/testpilot@labs.mozilla.com/modules/lib/url.js
-extensions/testpilot@labs.mozilla.com/modules/log4moz.js
-extensions/testpilot@labs.mozilla.com/modules/metadata.js
-extensions/testpilot@labs.mozilla.com/modules/Observers.js
-extensions/testpilot@labs.mozilla.com/modules/remote-experiment-loader.js
-extensions/testpilot@labs.mozilla.com/modules/setup.js
-extensions/testpilot@labs.mozilla.com/modules/string_sanitizer.js
-extensions/testpilot@labs.mozilla.com/modules/tasks.js
-extensions/testpilot@labs.mozilla.com/skin/all/badge-default.png
-extensions/testpilot@labs.mozilla.com/skin/all/bg.jpg
-extensions/testpilot@labs.mozilla.com/skin/all/css/screen-standalone.css
-extensions/testpilot@labs.mozilla.com/skin/all/dino_32x32.png
-extensions/testpilot@labs.mozilla.com/skin/all/images/bg-status.jpg
-extensions/testpilot@labs.mozilla.com/skin/all/images/callout.png
-extensions/testpilot@labs.mozilla.com/skin/all/images/callout_continue.png
-extensions/testpilot@labs.mozilla.com/skin/all/images/data1.jpg
-extensions/testpilot@labs.mozilla.com/skin/all/images/data2.jpg
-extensions/testpilot@labs.mozilla.com/skin/all/images/home_comments.png
-extensions/testpilot@labs.mozilla.com/skin/all/images/home_computer.png
-extensions/testpilot@labs.mozilla.com/skin/all/images/home_continue.png
-extensions/testpilot@labs.mozilla.com/skin/all/images/home_quit.png
-extensions/testpilot@labs.mozilla.com/skin/all/images/home_results.png
-extensions/testpilot@labs.mozilla.com/skin/all/images/home_twitter.png
-extensions/testpilot@labs.mozilla.com/skin/all/images/home_upcoming.png
-extensions/testpilot@labs.mozilla.com/skin/all/logo.png
-extensions/testpilot@labs.mozilla.com/skin/all/mozilla-logo.png
-extensions/testpilot@labs.mozilla.com/skin/all/status-completed.png
-extensions/testpilot@labs.mozilla.com/skin/all/status-ejected.png
-extensions/testpilot@labs.mozilla.com/skin/all/status-missed.png
-extensions/testpilot@labs.mozilla.com/skin/all/testpilot_16x16.png
-extensions/testpilot@labs.mozilla.com/skin/all/testPilot_200x200.png
-extensions/testpilot@labs.mozilla.com/skin/all/testpilot_32x32.png
-extensions/testpilot@labs.mozilla.com/skin/all/tp-completedstudies-32x32.png
-extensions/testpilot@labs.mozilla.com/skin/all/tp-currentstudies-32x32.png
-extensions/testpilot@labs.mozilla.com/skin/all/tp-generic-32x32.png
-extensions/testpilot@labs.mozilla.com/skin/all/tp-learned-32x32.png
-extensions/testpilot@labs.mozilla.com/skin/all/tp-results-48x48.png
-extensions/testpilot@labs.mozilla.com/skin/all/tp-settings-32x32.png
-extensions/testpilot@labs.mozilla.com/skin/all/tp-study-48x48.png
-extensions/testpilot@labs.mozilla.com/skin/all/tp-submit-48x48.png
-extensions/testpilot@labs.mozilla.com/skin/linux/close_button.png
-extensions/testpilot@labs.mozilla.com/skin/linux/feedback-frown-16x16.png
-extensions/testpilot@labs.mozilla.com/skin/linux/feedback-smile-16x16.png
-extensions/testpilot@labs.mozilla.com/skin/linux/feedback.css
-extensions/testpilot@labs.mozilla.com/skin/mac/close_button.png
-extensions/testpilot@labs.mozilla.com/skin/mac/feedback-frown-16x16.png
-extensions/testpilot@labs.mozilla.com/skin/mac/feedback-smile-16x16.png
-extensions/testpilot@labs.mozilla.com/skin/mac/feedback.css
-extensions/testpilot@labs.mozilla.com/skin/mac/notification-tail-down.png
-extensions/testpilot@labs.mozilla.com/skin/mac/notification-tail-up.png
-extensions/testpilot@labs.mozilla.com/skin/win/close_button.png
-extensions/testpilot@labs.mozilla.com/skin/win/feedback-frown-16x16.png
-extensions/testpilot@labs.mozilla.com/skin/win/feedback-smile-16x16.png
-extensions/testpilot@labs.mozilla.com/skin/win/feedback.css
-extensions/testpilot@labs.mozilla.com/skin/win/notification-tail-down.png
-extensions/testpilot@labs.mozilla.com/skin/win/notification-tail-up.png
-extensions/testpilot@labs.mozilla.com/tests/test_data_store.js
-extensions/uriloader@pdf.js.xpi
-greprefs/all.js
-greprefs/security-prefs.js
-greprefs/xpinstall.js
-install.rdf
-modules/JSON.jsm
-modules/SpatialNavigation.js
-modules/utils.js
-mozilla-runtime@BIN_SUFFIX@
-old-homepage-default.properties
-README.txt
-res/arrow.gif
-res/arrowd.gif
-res/broken-image.gif
-res/broken-image.png
-res/charsetData.properties
-res/charsetalias.properties
-res/cmessage.txt
-res/fonts/fontEncoding.properties
-res/fonts/fontNameMap.properties
-res/fonts/mathfontCMEX10.properties
-res/fonts/mathfontCMSY10.properties
-res/fonts/mathfontMTExtra.properties
-res/fonts/mathfontMath1.properties
-res/fonts/mathfontMath2.properties
-res/fonts/mathfontMath4.properties
-res/fonts/mathfontPUA.properties
-res/fonts/pangoFontEncoding.properties
-res/forms.css
-res/full-screen-override.css
-res/hiddenWindow.html
-res/html.css
-res/html/gopher-audio.gif
-res/html/gopher-binary.gif
-res/html/gopher-find.gif
-res/html/gopher-image.gif
-res/html/gopher-menu.gif
-res/html/gopher-movie.gif
-res/html/gopher-sound.gif
-res/html/gopher-telnet.gif
-res/html/gopher-text.gif
-res/html/gopher-unknown.gif
-res/loading-image.gif
-res/loading-image.png
-res/maccharset.properties
-res/mathml.css
-res/os2charset.properties
-res/quirk.css
-res/ua.css
-res/unixcharset.properties
-res/viewsource.css
-res/wincharset.properties
+extensions/
+extensions/inspector@mozilla.org/*
+extensions/reporter@mozilla.org/*
+extensions/talkback@mozilla.org/*
+extensions/testpilot@labs.mozilla.com/*
+extensions/{641d8d09-7dda-4850-8228-ac0ab65e2ac9}/*
+extensions/{972ce4c6-7e08-4474-a285-3208198ce6fd}/*
+greprefs/
+jssubloader/
+modules/
 #ifdef XP_MACOSX
-run-mozilla.sh
-#endif
-searchplugins/DRAE.gif
-searchplugins/DRAE.png
-searchplugins/DRAE.src
-searchplugins/MediaDICO-fr.gif
-searchplugins/MediaDICO-fr.png
-searchplugins/MediaDICO-fr.src
-searchplugins/allegro-pl.gif
-searchplugins/allegro-pl.png
-searchplugins/allegro-pl.src
-searchplugins/amazon-de.gif
-searchplugins/amazon-de.png
-searchplugins/amazon-de.src
-searchplugins/amazon-en-GB.gif
-searchplugins/amazon-en-GB.png
-searchplugins/amazon-en-GB.src
-searchplugins/amazon-france.gif
-searchplugins/amazon-france.png
-searchplugins/amazon-france.src
-searchplugins/amazon-jp.gif
-searchplugins/amazon-jp.png
-searchplugins/amazon-jp.src
-searchplugins/amazondotcom-zh-TW.gif
-searchplugins/amazondotcom-zh-TW.png
-searchplugins/amazondotcom-zh-TW.src
-searchplugins/amazondotcom.gif
-searchplugins/amazondotcom.png
-searchplugins/amazondotcom.png
-searchplugins/amazondotcom.src
-searchplugins/amazondotcom.src
-searchplugins/answers.gif
-searchplugins/answers.png
-searchplugins/answers.png
-searchplugins/answers.src
-searchplugins/answers.src
-searchplugins/atlas-sk.gif
-searchplugins/atlas-sk.png
-searchplugins/atlas-sk.src
-searchplugins/baidu.gif
-searchplugins/baidu.png
-searchplugins/baidu.src
-searchplugins/bluu.xml
-searchplugins/bok-NO.gif
-searchplugins/bok-NO.png
-searchplugins/bok-NO.src
-searchplugins/bolcom-nl.gif
-searchplugins/bolcom-nl.png
-searchplugins/bolcom-nl.src
-searchplugins/bookplus-fi.gif
-searchplugins/bookplus-fi.png
-searchplugins/bookplus-fi.src
-searchplugins/caplex-NO.gif
-searchplugins/caplex-NO.png
-searchplugins/caplex-NO.src
-searchplugins/centrum-cz.gif
-searchplugins/centrum-cz.png
-searchplugins/centrum-cz.src
-searchplugins/centrum-cz.xml
-searchplugins/creativecommons-fi.gif
-searchplugins/creativecommons-fi.png
-searchplugins/creativecommons-fi.src
-searchplugins/creativecommons-it.gif
-searchplugins/creativecommons-it.png
-searchplugins/creativecommons-it.src
-searchplugins/creativecommons-zh-TW.gif
-searchplugins/creativecommons-zh-TW.png
-searchplugins/creativecommons-zh-TW.src
-searchplugins/creativecommons.gif
-searchplugins/creativecommons.png
-searchplugins/creativecommons.png
-searchplugins/creativecommons.src
-searchplugins/creativecommons.src
-searchplugins/daum-ko.gif
-searchplugins/daum-ko.png
-searchplugins/daum-ko.src
-searchplugins/demauro-it.gif
-searchplugins/demauro-it.png
-searchplugins/demauro-it.src
-searchplugins/dictionary-en-GB.gif
-searchplugins/dictionary-en-GB.png
-searchplugins/dictionary-en-GB.src
-searchplugins/dictionary.png
-searchplugins/dictionary.src
-searchplugins/dunaj-sk.gif
-searchplugins/dunaj-sk.png
-searchplugins/dunaj-sk.src
-searchplugins/eBay-de.gif
-searchplugins/eBay-de.png
-searchplugins/eBay-de.src
-searchplugins/eBay-en-GB.gif
-searchplugins/eBay-en-GB.png
-searchplugins/eBay-en-GB.src
-searchplugins/eBay-france.gif
-searchplugins/eBay-france.png
-searchplugins/eBay-france.src
-searchplugins/eBay-fy-NL.xml
-searchplugins/eBay-gu.gif
-searchplugins/eBay-gu.png
-searchplugins/eBay-gu.src
-searchplugins/eBay-nl.gif
-searchplugins/eBay-nl.png
-searchplugins/eBay-nl.src
-searchplugins/eBay-nl.xml
-searchplugins/eBay-zh-CN.gif
-searchplugins/eBay-zh-CN.png
-searchplugins/eBay-zh-CN.src
-searchplugins/eBay-zh-CN.xml
-searchplugins/eBay-zh-TW.gif
-searchplugins/eBay-zh-TW.png
-searchplugins/eBay-zh-TW.src
-searchplugins/eBay-zh-TW.xml
-searchplugins/eBay.gif
-searchplugins/eBay.gif
-searchplugins/eBay.png
-searchplugins/eBay.src
-searchplugins/eBay.src
-searchplugins/ebay-it.gif
-searchplugins/ebay-it.png
-searchplugins/ebay-it.src
-searchplugins/filesearchru.gif
-searchplugins/filesearchru.png
-searchplugins/filesearchru.src
-searchplugins/filesearchru.xml
-searchplugins/goo.gif
-searchplugins/goo.png
-searchplugins/goo.src
-searchplugins/goo.xml
-searchplugins/google-NO.gif
-searchplugins/google-NO.png
-searchplugins/google-NO.src
-searchplugins/google-ar.gif
-searchplugins/google-ar.png
-searchplugins/google-ar.src
-searchplugins/google-ar.xml
-searchplugins/google-bg.gif
-searchplugins/google-bg.png
-searchplugins/google-bg.src
-searchplugins/google-ca.gif
-searchplugins/google-ca.png
-searchplugins/google-ca.src
-searchplugins/google-de.gif
-searchplugins/google-de.png
-searchplugins/google-de.src
-searchplugins/google-dk.gif
-searchplugins/google-dk.png
-searchplugins/google-dk.src
-searchplugins/google-en-GB.gif
-searchplugins/google-en-GB.png
-searchplugins/google-en-GB.src
-searchplugins/google-es-ES.gif
-searchplugins/google-es-ES.png
-searchplugins/google-es-ES.src
-searchplugins/google-eu.gif
-searchplugins/google-eu.png
-searchplugins/google-eu.src
-searchplugins/google-fi.gif
-searchplugins/google-fi.png
-searchplugins/google-fi.src
-searchplugins/google-ga-IE.gif
-searchplugins/google-ga-IE.png
-searchplugins/google-ga-IE.src
-searchplugins/google-gu.gif
-searchplugins/google-gu.png
-searchplugins/google-gu.src
-searchplugins/google-it.gif
-searchplugins/google-it.png
-searchplugins/google-it.src
-searchplugins/google-jp.gif
-searchplugins/google-jp.png
-searchplugins/google-jp.src
-searchplugins/google-ko.gif
-searchplugins/google-ko.png
-searchplugins/google-ko.src
-searchplugins/google-lt.gif
-searchplugins/google-lt.png
-searchplugins/google-lt.src
-searchplugins/google-nl.gif
-searchplugins/google-nl.png
-searchplugins/google-nl.src
-searchplugins/google-pl.gif
-searchplugins/google-pl.png
-searchplugins/google-pl.src
-searchplugins/google-pt-BR.gif
-searchplugins/google-pt-BR.png
-searchplugins/google-pt-BR.src
-searchplugins/google-ro.gif
-searchplugins/google-ro.png
-searchplugins/google-ro.src
-searchplugins/google-ru.gif
-searchplugins/google-ru.png
-searchplugins/google-ru.src
-searchplugins/google-sl.gif
-searchplugins/google-sl.png
-searchplugins/google-sl.src
-searchplugins/google-zh-TW.gif
-searchplugins/google-zh-TW.png
-searchplugins/google-zh-TW.src
-searchplugins/google.gif
-searchplugins/google.gif
-searchplugins/google.png
-searchplugins/google.src
-searchplugins/google.src
-searchplugins/grandiccionari.gif
-searchplugins/grandiccionari.png
-searchplugins/grandiccionari.src
-searchplugins/grandiccionari.xml
-searchplugins/huuto-fi.gif
-searchplugins/huuto-fi.png
-searchplugins/huuto-fi.src
-searchplugins/jyxo-cz.gif
-searchplugins/jyxo-cz.png
-searchplugins/jyxo-cz.src
-searchplugins/lingvo.yandex.ru.gif
-searchplugins/lingvo.yandex.ru.png
-searchplugins/lingvo.yandex.ru.src
-searchplugins/lingvo.yandex.ru.xml
-searchplugins/llibres.gif
-searchplugins/llibres.png
-searchplugins/llibres.src
-searchplugins/mall-cz.gif
-searchplugins/mall-cz.png
-searchplugins/mall-cz.src
-searchplugins/mercadolivre-com-br.gif
-searchplugins/mercadolivre-com-br.png
-searchplugins/mercadolivre-com-br.src
-searchplugins/merlin-pl.gif
-searchplugins/merlin-pl.png
-searchplugins/merlin-pl.src
-searchplugins/najdi-si.gif
-searchplugins/najdi-si.png
-searchplugins/najdi-si.src
-searchplugins/nana.xml
-searchplugins/naver-ko.gif
-searchplugins/naver-ko.png
-searchplugins/naver-ko.src
-searchplugins/netex.xml
-searchplugins/nosaltres.gif
-searchplugins/nosaltres.png
-searchplugins/nosaltres.src
-searchplugins/nosaltres.xml
-searchplugins/pbi-pl.gif
-searchplugins/pbi-pl.png
-searchplugins/pbi-pl.src
-searchplugins/pbi-pl.xml
-searchplugins/priceru.gif
-searchplugins/priceru.png
-searchplugins/priceru.src
-searchplugins/pwn-pl.gif
-searchplugins/pwn-pl.png
-searchplugins/pwn-pl.src
-searchplugins/qxl-NO.gif
-searchplugins/qxl-NO.png
-searchplugins/qxl-NO.src
-searchplugins/rakuten.gif
-searchplugins/rakuten.png
-searchplugins/rakuten.src
-searchplugins/rambler.xml
-searchplugins/seznam-cz.gif
-searchplugins/seznam-cz.png
-searchplugins/seznam-cz.src
-searchplugins/sigov-gov-si.gif
-searchplugins/sigov-gov-si.png
-searchplugins/sigov-gov-si.src
-searchplugins/slunecnice-cz.gif
-searchplugins/slunecnice-cz.png
-searchplugins/slunecnice-cz.src
-searchplugins/submarino-com-br.gif
-searchplugins/submarino-com-br.png
-searchplugins/submarino-com-br.src
-searchplugins/taobao.gif
-searchplugins/taobao.png
-searchplugins/taobao.src
-searchplugins/taobao.xml
-searchplugins/telefonkatalogen-NO.gif
-searchplugins/telefonkatalogen-NO.png
-searchplugins/telefonkatalogen-NO.src
-searchplugins/termiadur.xml
-searchplugins/universal-pt.gif
-searchplugins/universal-pt.png
-searchplugins/universal-pt.src
-searchplugins/vandale-nl.gif
-searchplugins/vandale-nl.png
-searchplugins/vandale-nl.src
-searchplugins/walla_sites.gif
-searchplugins/walla_sites.png
-searchplugins/walla_sites.src
-searchplugins/wikipedia-bg.gif
-searchplugins/wikipedia-bg.png
-searchplugins/wikipedia-bg.src
-searchplugins/wikipedia-ca.gif
-searchplugins/wikipedia-ca.png
-searchplugins/wikipedia-ca.src
-searchplugins/wikipedia-de.gif
-searchplugins/wikipedia-de.png
-searchplugins/wikipedia-de.src
-searchplugins/wikipedia-en-CN.xml
-searchplugins/wikipedia-es-ES.gif
-searchplugins/wikipedia-es-ES.png
-searchplugins/wikipedia-es-ES.src
-searchplugins/wikipedia-eu.gif
-searchplugins/wikipedia-eu.png
-searchplugins/wikipedia-eu.src
-searchplugins/wikipedia-fi.gif
-searchplugins/wikipedia-fi.png
-searchplugins/wikipedia-fi.src
-searchplugins/wikipedia-fr.gif
-searchplugins/wikipedia-fr.png
-searchplugins/wikipedia-fr.src
-searchplugins/wikipedia-fy.gif
-searchplugins/wikipedia-fy.png
-searchplugins/wikipedia-fy.src
-searchplugins/wikipedia-he.gif
-searchplugins/wikipedia-he.png
-searchplugins/wikipedia-he.src
-searchplugins/wikipedia-it.gif
-searchplugins/wikipedia-it.png
-searchplugins/wikipedia-it.src
-searchplugins/wikipedia-lt.gif
-searchplugins/wikipedia-lt.png
-searchplugins/wikipedia-lt.src
-searchplugins/wikipedia-nl.gif
-searchplugins/wikipedia-nl.png
-searchplugins/wikipedia-nl.src
-searchplugins/wikipedia-pl.gif
-searchplugins/wikipedia-pl.png
-searchplugins/wikipedia-pl.src
-searchplugins/wikipedia-ru.gif
-searchplugins/wikipedia-ru.png
-searchplugins/wikipedia-ru.src
-searchplugins/wikipedia-sk.gif
-searchplugins/wikipedia-sk.png
-searchplugins/wikipedia-sk.src
-searchplugins/wikipedia-zh.xml
-searchplugins/wp-pl.gif
-searchplugins/wp-pl.png
-searchplugins/wp-pl.src
-searchplugins/yahoo-NO.gif
-searchplugins/yahoo-NO.png
-searchplugins/yahoo-NO.src
-searchplugins/yahoo-ar.gif
-searchplugins/yahoo-ar.png
-searchplugins/yahoo-ar.src
-searchplugins/yahoo-ca.gif
-searchplugins/yahoo-ca.png
-searchplugins/yahoo-ca.src
-searchplugins/yahoo-cn.gif
-searchplugins/yahoo-cn.png
-searchplugins/yahoo-cn.src
-searchplugins/yahoo-de.gif
-searchplugins/yahoo-de.png
-searchplugins/yahoo-de.src
-searchplugins/yahoo-dk.gif
-searchplugins/yahoo-dk.png
-searchplugins/yahoo-dk.src
-searchplugins/yahoo-en-GB.gif
-searchplugins/yahoo-en-GB.png
-searchplugins/yahoo-en-GB.src
-searchplugins/yahoo-es-ES.gif
-searchplugins/yahoo-es-ES.png
-searchplugins/yahoo-es-ES.src
-searchplugins/yahoo-fi.gif
-searchplugins/yahoo-fi.png
-searchplugins/yahoo-fi.src
-searchplugins/yahoo-france.gif
-searchplugins/yahoo-france.png
-searchplugins/yahoo-france.src
-searchplugins/yahoo-gu.gif
-searchplugins/yahoo-gu.png
-searchplugins/yahoo-gu.src
-searchplugins/yahoo-it.gif
-searchplugins/yahoo-it.png
-searchplugins/yahoo-it.src
-searchplugins/yahoo-jp-auctions.gif
-searchplugins/yahoo-jp-auctions.png
-searchplugins/yahoo-jp-auctions.src
-searchplugins/yahoo-jp-shopping.gif
-searchplugins/yahoo-jp-shopping.png
-searchplugins/yahoo-jp-shopping.src
-searchplugins/yahoo-jp-shopping.xml
-searchplugins/yahoo-jp.gif
-searchplugins/yahoo-jp.png
-searchplugins/yahoo-jp.src
-searchplugins/yahoo-kr.gif
-searchplugins/yahoo-kr.png
-searchplugins/yahoo-kr.src
-searchplugins/yahoo-nl.gif
-searchplugins/yahoo-nl.png
-searchplugins/yahoo-nl.src
-searchplugins/yahoo-pt-BR.gif
-searchplugins/yahoo-pt-BR.png
-searchplugins/yahoo-pt-BR.src
-searchplugins/yahoo-ru.xml
-searchplugins/yahoo-tw.gif
-searchplugins/yahoo-tw.png
-searchplugins/yahoo-tw.src
-searchplugins/yahoo-zh-CN.xml
-searchplugins/yahoo.gif
-searchplugins/yahoo.gif
-searchplugins/yahoo.png
-searchplugins/yahoo.src
-searchplugins/yahoo.src
-searchplugins/yandex.gif
-searchplugins/yandex.png
-searchplugins/yandex.src
-searchplugins/zoznam-sk.gif
-searchplugins/zoznam-sk.png
-searchplugins/zoznam-sk.src
-uninstall/UninstallDeerPark.exe
-uninstall/UninstallFirefox.exe
-uninstall/uninst.exe
-uninstall/uninstall.exe
-#ifndef MOZ_UPDATER
-  #ifdef XP_MACOSX
-    updater.app/
-  #else
-    updater@BIN_SUFFIX@
-  #endif
-  updater.ini
+  plugins/Default Plugin.plugin/*
+  plugins/JavaEmbeddingPlugin.bundle/*
+  plugins/MRJPlugin.plugin/*
+  ../Plug-Ins/PrintPDE.plugin/*
 #endif
-xpicleanup@BIN_SUFFIX@
-#ifdef MOZ_OMNIJAR
-  update.locale
-  omni.jar
-  chrome/af.jar
-  chrome/af.manifest
-  chrome/ar.jar
-  chrome/ar.manifest
-  chrome/as.jar
-  chrome/as.manifest
-  chrome/ast.jar
-  chrome/ast.manifest
-  chrome/be.jar
-  chrome/be.manifest
-  chrome/bg.jar
-  chrome/bg.manifest
-  chrome/bn-BD.jar
-  chrome/bn-BD.manifest
-  chrome/bn-IN.jar
-  chrome/bn-IN.manifest
-  chrome/ca.jar
-  chrome/ca.manifest
-  chrome/cs.jar
-  chrome/cs.manifest
-  chrome/cy.jar
-  chrome/cy.manifest
-  chrome/da.jar
-  chrome/da.manifest
-  chrome/de.jar
-  chrome/de.manifest
-  chrome/el.jar
-  chrome/el.manifest
-  chrome/en-GB.jar
-  chrome/en-GB.manifest
-  chrome/en-US.jar
-  chrome/en-US.manifest
-  chrome/eo.jar
-  chrome/eo.manifest
-  chrome/es-AR.jar
-  chrome/es-AR.manifest
-  chrome/es-CL.jar
-  chrome/es-CL.manifest
-  chrome/es-ES.jar
-  chrome/es-ES.manifest
-  chrome/es-MX.jar
-  chrome/es-MX.manifest
-  chrome/et.jar
-  chrome/et.manifest
-  chrome/eu.jar
-  chrome/eu.manifest
-  chrome/fa.jar
-  chrome/fa.manifest
-  chrome/fi.jar
-  chrome/fi.manifest
-  chrome/fr.jar
-  chrome/fr.manifest
-  chrome/fy-NL.jar
-  chrome/fy-NL.manifest
-  chrome/ga-IE.jar
-  chrome/ga-IE.manifest
-  chrome/gd.jar
-  chrome/gd.manifest
-  chrome/gl.jar
-  chrome/gl.manifest
-  chrome/gu-IN.jar
-  chrome/gu-IN.manifest
-  chrome/he.jar
-  chrome/he.manifest
-  chrome/hi-IN.jar
-  chrome/hi-IN.manifest
-  chrome/hr.jar
-  chrome/hr.manifest
-  chrome/hu.jar
-  chrome/hu.manifest
-  chrome/id.jar
-  chrome/id.manifest
-  chrome/is.jar
-  chrome/is.manifest
-  chrome/it.jar
-  chrome/it.manifest
-  chrome/ja-JP-mac.jar
-  chrome/ja-JP-mac.manifest
-  chrome/ja.jar
-  chrome/ja.manifest
-  chrome/ka.jar
-  chrome/ka.manifest
-  chrome/kk.jar
-  chrome/kk.manifest
-  chrome/kn.jar
-  chrome/kn.manifest
-  chrome/ko.jar
-  chrome/ko.manifest
-  chrome/ku.jar
-  chrome/ku.manifest
-  chrome/lt.jar
-  chrome/lt.manifest
-  chrome/lv.jar
-  chrome/lv.manifest
-  chrome/mk.jar
-  chrome/mk.manifest
-  chrome/ml.jar
-  chrome/ml.manifest
-  chrome/mn.jar
-  chrome/mn.manifest
-  chrome/mr.jar
-  chrome/mr.manifest
-  chrome/nb-NO.jar
-  chrome/nb-NO.manifest
-  chrome/nl.jar
-  chrome/nl.manifest
-  chrome/nn-NO.jar
-  chrome/nn-NO.manifest
-  chrome/oc.jar
-  chrome/oc.manifest
-  chrome/or.jar
-  chrome/or.manifest
-  chrome/pa-IN.jar
-  chrome/pa-IN.manifest
-  chrome/pl.jar
-  chrome/pl.manifest
-  chrome/pt-BR.jar
-  chrome/pt-BR.manifest
-  chrome/pt-PT.jar
-  chrome/pt-PT.manifest
-  chrome/rm.jar
-  chrome/rm.manifest
-  chrome/ro.jar
-  chrome/ro.manifest
-  chrome/ru.jar
-  chrome/ru.manifest
-  chrome/si.jar
-  chrome/si.manifest
-  chrome/sk.jar
-  chrome/sk.manifest
-  chrome/sl.jar
-  chrome/sl.manifest
-  chrome/sq.jar
-  chrome/sq.manifest
-  chrome/sr.jar
-  chrome/sr.manifest
-  chrome/sv-SE.jar
-  chrome/sv-SE.manifest
-  chrome/ta-LK.jar
-  chrome/ta-LK.manifest
-  chrome/ta.jar
-  chrome/ta.manifest
-  chrome/te.jar
-  chrome/te.manifest
-  chrome/th.jar
-  chrome/th.manifest
-  chrome/tr.jar
-  chrome/tr.manifest
-  chrome/uk.jar
-  chrome/uk.manifest
-  chrome/vi.jar
-  chrome/vi.manifest
-  chrome/zh-CN.jar
-  chrome/zh-CN.manifest
-  chrome/zh-TW.jar
-  chrome/zh-TW.manifest
-  chrome/browser.jar
-  chrome/localized.manifest
-  chrome/nonlocalized.manifest
-  chrome/pippki.jar
-  chrome/toolkit.jar
-  components/addonManager.js
-  components/Aitc.js
-  components/AitcComponents.manifest
-  components/amContentHandler.js
-  components/amWebInstallListener.js
-  components/binary.manifest
-  components/browser.xpt
-  components/BrowserElementParent.js
-  components/BrowserElementParent.manifest
-  components/BrowserElementPromptService.jsm
-  components/BrowserElementParent.jsm
-  components/contentAreaDropListener.js
-  components/contentSecurityPolicy.js
-  components/crypto-SDR.js
-  components/FeedConverter.js
-  components/FeedProcessor.js
-  components/FeedWriter.js
-  components/fuelApplication.js
-  components/GPSDGeolocationProvider.js
-  components/interfaces.manifest
-  components/jsconsole-clhandler.js
-  components/MetricsCollectionService.js
-  components/NetworkGeolocationProvider.js
-  components/NotificationsComponents.manifest
-  components/nsBadCertHandler.js
-  components/nsBlocklistService.js
-  components/nsBrowserContentHandler.js
-  components/nsBrowserGlue.js
-  components/nsContentDispatchChooser.js
-  components/nsContentPrefService.js
-  components/nsDefaultCLH.js
-  components/nsDownloadManagerUI.js
-  #ifdef XP_UNIX
-    #ifndef XP_MACOSX
-      components/nsFilePicker.js
-    #endif
-  #endif
-  components/nsFormAutoComplete.js
-  components/nsFormHistory.js
-  components/nsHandlerService.js
-  components/nsHelperAppDlg.js
-  components/nsINIProcessor.js
-  components/nsLivemarkService.js
-  components/nsLoginInfo.js
-  components/nsLoginManager.js
-  components/nsLoginManagerPrompter.js
-  components/nsPlacesAutoComplete.js
-  components/nsPlacesDBFlush.js
-  components/nsPlacesExpiration.js
-  components/nsPrivateBrowsingService.js
-  components/nsPrompter.js
-  components/nsProxyAutoConfig.manifest
-  components/nsProxyAutoConfig.js
-  components/nsSafebrowsingApplication.js
-  components/nsSearchService.js
-  components/nsSearchSuggestions.js
-  components/nsSessionStartup.js
-  components/nsSessionStore.js
-  components/nsSetDefaultBrowser.js
-  components/nsSidebar.js
-  components/nsTaggingService.js
-  components/nsTryToClose.js
-  components/nsUpdateService.js
-  components/nsUpdateServiceStub.js
-  components/nsUpdateTimerManager.js
-  components/nsUrlClassifierLib.js
-  components/nsUrlClassifierListManager.js
-  components/nsURLFormatter.js
-  components/nsWebHandlerApp.js
-  components/PlacesProtocolHandler.js
-  components/storage-Legacy.js
-  components/storage-mozStorage.js
-#ifdef MOZ_B2G_RIL
-  components/nsTelephonyWorker.manifest
-  components/nsTelephonyWorker.js
-  components/Telephony.manifest
-  components/Telephony.js
-  components/WifiWorker.js
-  components/WifiWorker.manifest
-  components/DOMWifiManager.js
-  components/DOMWifiManager.manifest
-#endif
-  components/txEXSLTRegExFunctions.js
-  components/Weave.js
-  components/Webapps.js
-  components/Webapps.manifest
-  components/WebContentConverter.js
-  defaults/autoconfig/platform.js
-  defaults/autoconfig/prefcalls.js
-  defaults/pref/firefox-branding.js
-  defaults/pref/firefox.js
-  defaults/pref/firefox-l10n.js
-  defaults/pref/services-sync.js
-  defaults/profile/bookmarks.html
-  defaults/profile/chrome/userChrome-example.css
-  defaults/profile/chrome/userContent-example.css
-  defaults/profile/localstore.rdf
-  defaults/profile/mimeTypes.rdf
-  defaults/profile/prefs.js
-  greprefs.js
-  hyphenation/
-  hyphenation/hyph_af.dic
-  hyphenation/hyph_bg.dic
-  hyphenation/hyph_ca.dic
-  hyphenation/hyph_cy.dic
-  hyphenation/hyph_da.dic
-  hyphenation/hyph_de-1901.dic
-  hyphenation/hyph_de-1996.dic
-  hyphenation/hyph_de-CH.dic
-  hyphenation/hyph_en_US.dic
-  hyphenation/hyph_eo.dic
-  hyphenation/hyph_es.dic
-  hyphenation/hyph_et.dic
-  hyphenation/hyph_fi.dic
-  hyphenation/hyph_fr.dic
-  hyphenation/hyph_gl.dic
-  hyphenation/hyph_hr.dic
-  hyphenation/hyph_hsb.dic
-  hyphenation/hyph_hu.dic
-  hyphenation/hyph_ia.dic
-  hyphenation/hyph_is.dic
-  hyphenation/hyph_it.dic
-  hyphenation/hyph_kmr.dic
-  hyphenation/hyph_la.dic
-  hyphenation/hyph_lt.dic
-  hyphenation/hyph_mn.dic
-  hyphenation/hyph_nb.dic
-  hyphenation/hyph_nl.dic
-  hyphenation/hyph_nn.dic
-  hyphenation/hyph_pt.dic
-  hyphenation/hyph_ru.dic
-  hyphenation/hyph_sh.dic
-  hyphenation/hyph_sl.dic
-  hyphenation/hyph_sv.dic
-  hyphenation/hyph_tr.dic
-  hyphenation/hyph_uk.dic
-  modules/AddonLogging.jsm
-  modules/AddonManager.jsm
-  modules/AddonRepository.jsm
-  modules/AddonUpdateChecker.jsm
-  modules/CertUtils.jsm
-  modules/CrashSubmit.jsm
-  modules/CSPUtils.jsm
-  modules/ctypes.jsm
-  modules/debug.js
-  modules/distribution.js
-  modules/DownloadLastDir.jsm
-  modules/DownloadPaths.jsm
-  #ifdef XP_WIN
-    modules/DownloadTaskbarProgress.jsm
-  #endif
-  modules/DownloadUtils.jsm
-  modules/FileUtils.jsm
-  modules/Geometry.jsm
-  modules/HUDService.jsm
-  modules/InlineSpellChecker.jsm
-  modules/ISO8601DateUtils.jsm
-  modules/LightweightThemeConsumer.jsm
-  modules/LightweightThemeManager.jsm
-  modules/Microformats.js
-  modules/NetUtil.jsm
-  modules/NetworkPrioritizer.jsm
-  modules/openLocationLastURL.jsm
-  modules/PerfMeasurement.jsm
-  modules/PlacesDBUtils.jsm
-  modules/PlacesUIUtils.jsm
-  modules/PlacesUtils.jsm
-  modules/PluginProvider.jsm
-  modules/PluralForm.jsm
-  modules/PopupNotifications.jsm
-  modules/reflect.jsm
-  modules/Services.jsm
-  modules/services-common/async.js
-  modules/services-common/log4moz.js
-  modules/services-common/observers.js
-  modules/services-common/preferences.js
-  modules/services-common/rest.js
-  modules/services-common/stringbundle.js
-  modules/services-common/utils.js
-  modules/services-notifications/service.js
-  modules/services-sync/auth.js
-  modules/services-sync/base_records/collection.js
-  modules/services-sync/base_records/crypto.js
-  modules/services-sync/base_records/keys.js
-  modules/services-sync/base_records/wbo.js
-  modules/services-sync/constants.js
-  modules/services-sync/engines/bookmarks.js
-  modules/services-sync/engines/clients.js
-  modules/services-sync/engines/forms.js
-  modules/services-sync/engines/history.js
-  modules/services-sync/engines.js
-  modules/services-sync/engines/passwords.js
-  modules/services-sync/engines/prefs.js
-  modules/services-sync/engines/tabs.js
-  modules/services-sync/ext/Observers.js
-  modules/services-sync/ext/Preferences.js
-  modules/services-sync/ext/StringBundle.js
-  modules/services-sync/ext/Sync.js
-  modules/services-sync/identity.js
-  modules/services-sync/log4moz.js
-  modules/services-sync/notifications.js
-  modules/services-sync/resource.js
-  modules/services-sync/service.js
-  modules/services-sync/status.js
-  modules/services-sync/stores.js
-  modules/services-sync/trackers.js
-  modules/services-sync/type_records/bookmark.js
-  modules/services-sync/type_records/clients.js
-  modules/services-sync/type_records/forms.js
-  modules/services-sync/type_records/history.js
-  modules/services-sync/type_records/passwords.js
-  modules/services-sync/type_records/prefs.js
-  modules/services-sync/type_records/tabs.js
-  modules/services-sync/util.js
-  modules/stylePanel.jsm
-  modules/tabview/AllTabs.jsm
-  modules/tabview/groups.jsm
-  modules/tabview/utils.jsm
-  modules/Webapps.jsm
-  modules/WindowDraggingUtils.jsm
-  #ifdef XP_WIN
-    modules/WindowsJumpLists.jsm
-    modules/WindowsPreviewPerTab.jsm
-  #endif
-  modules/XPCOMUtils.jsm
-  modules/XPIProvider.jsm
-  res/contenteditable.css
-  res/designmode.css
-  res/dtd/mathml.dtd
-  res/dtd/xhtml11.dtd
-  res/EditorOverride.css
-  res/entityTables/html40Latin1.properties
-  res/entityTables/html40Special.properties
-  res/entityTables/html40Symbols.properties
-  res/entityTables/htmlEntityVersions.properties
-  res/entityTables/mathml20.properties
-  res/entityTables/transliterate.properties
-  res/fonts/mathfont.properties
-  res/fonts/mathfontStandardSymbolsL.properties
-  res/fonts/mathfontSTIXNonUnicode.properties
-  res/fonts/mathfontSTIXSize1.properties
-  res/fonts/mathfontSTIXSizeOneSym.properties
-  #ifdef XP_WIN
-    res/fonts/mathfontSymbol.properties
-  #endif
-  res/fonts/mathfontUnicode.properties
-  res/grabber.gif
-  res/html/folder.png
-  res/langGroups.properties
-  res/language.properties
-  res/svg.css
-  res/table-add-column-after-active.gif
-  res/table-add-column-after.gif
-  res/table-add-column-after-hover.gif
-  res/table-add-column-before-active.gif
-  res/table-add-column-before.gif
-  res/table-add-column-before-hover.gif
-  res/table-add-row-after-active.gif
-  res/table-add-row-after.gif
-  res/table-add-row-after-hover.gif
-  res/table-add-row-before-active.gif
-  res/table-add-row-before.gif
-  res/table-add-row-before-hover.gif
-  res/table-remove-column-active.gif
-  res/table-remove-column.gif
-  res/table-remove-column-hover.gif
-  res/table-remove-row-active.gif
-  res/table-remove-row.gif
-  res/table-remove-row-hover.gif
-#else
-  components/binary.manifest
-  omni.jar
-  omni.ja
-#endif
-#ifdef XP_MACOSX
-  ../Plug-Ins/PrintPDE.plugin/Contents/Info.plist
-  ../Plug-Ins/PrintPDE.plugin/Contents/MacOS/PrintPDE
-  ../Plug-Ins/PrintPDE.plugin/Contents/Resources/English.lproj/Localizable.strings
-  ../Plug-Ins/PrintPDE.plugin/Contents/Resources/English.lproj/PrintPDE.nib/classes.nib
-  ../Plug-Ins/PrintPDE.plugin/Contents/Resources/English.lproj/PrintPDE.nib/info.nib
-  ../Plug-Ins/PrintPDE.plugin/Contents/Resources/English.lproj/PrintPDE.nib/objects.xib
-  ../Resources/firefox-bin.rsrc
-  components/accessibility.xpt
-  components/alerts.xpt
-  components/appshell.xpt
-  components/appstartup.xpt
-  components/autoconfig.xpt
-  components/browser-feeds.xpt
-  components/browsercompsbase.xpt
-  components/browsersearch.xpt
-  components/caps.xpt
-  components/chardet.xpt
-  components/chrome.xpt
-  components/commandhandler.xpt
-  components/commandlines.xpt
-  components/composer.xpt
-  components/content.xpt
-  components/content_base.xpt
-  components/content_html.xpt
-  components/content_htmldoc.xpt
-  components/content_xmldoc.xpt
-  components/content_xslt.xpt
-  components/content_xtf.xpt
-  components/contentprefs.xpt
-  components/cookie.xpt
-  components/crashreporter.xpt
-  components/directory.xpt
-  components/docshell.xpt
-  components/dom.xpt
-  components/dom_apps.xpt
-  components/dom_base.xpt
-#ifdef MOZ_B2G_RIL
-  components/dom_telephony.xpt
-  components/dom_wifi.xpt
-  components/dom_system_b2g.xpt
-#endif
-  components/dom_canvas.xpt
-  components/dom_core.xpt
-  components/dom_css.xpt
-  components/dom_events.xpt
-  components/dom_geolocation.xpt
-  components/dom_devicestorage.xpt
-  components/dom_html.xpt
-  components/dom_json.xpt
-  components/dom_loadsave.xpt
-  components/dom_offline.xpt
-  components/dom_push.xpt
-  components/dom_range.xpt
-  components/dom_sidebar.xpt
-  components/dom_smil.xpt
-  components/dom_storage.xpt
-  components/dom_stylesheets.xpt
-  components/dom_svg.xpt
-  components/dom_threads.xpt
-  components/dom_traversal.xpt
-  components/dom_views.xpt
-  components/dom_xbl.xpt
-  components/dom_xpath.xpt
-  components/dom_xul.xpt
-  components/downloads.xpt
-  components/editor.xpt
-  components/embed_base.xpt
-  components/extensions.xpt
-  components/exthandler.xpt
-  components/exthelper.xpt
-  components/fastfind.xpt
-  components/feeds.xpt
-  components/find.xpt
-  components/firefox.xpt
-  components/fuel.xpt
-  components/gfx.xpt
-  components/gksvgrenderer.xpt
-  components/html5.xpt
-  components/htmlparser.xpt
-  components/imgicon.xpt
-  components/imglib2.xpt
-  components/inspector.xpt
-  components/intl.xpt
-  components/jar.xpt
-  components/jsconsole.xpt
-  components/jsdservice.xpt
-  components/layout_base.xpt
-  components/layout_printing.xpt
-  components/layout_xul.xpt
-  components/layout_xul_tree.xpt
-  components/locale.xpt
-  components/loginmgr.xpt
-  components/lwbrk.xpt
-  components/migration.xpt
-  components/mimetype.xpt
-  components/mozbrwsr.xpt
-  components/mozfind.xpt
-  components/necko.xpt
-  components/necko_about.xpt
-  components/necko_cache.xpt
-  components/necko_cookie.xpt
-  components/necko_data.xpt
-  components/necko_dns.xpt
-  components/necko_file.xpt
-  components/necko_ftp.xpt
-  components/necko_http.xpt
-  components/necko_res.xpt
-  components/necko_socket.xpt
-  components/necko_strconv.xpt
-  components/necko_viewsource.xpt
-  components/necko_wifi.xpt
-  components/nsKillAll.js
-  components/nsProgressDialog.js
-  components/nsResetPref.js
-  components/oji.xpt
-  components/parentalcontrols.xpt
-  components/passwordmgr.xpt
-  components/pipboot.xpt
-  components/pipnss.xpt
-  components/pippki.xpt
-  components/places.xpt
-  components/plugin.xpt
-  components/pref.xpt
-  components/prefetch.xpt
-  components/profile.xpt
-  components/progressDlg.xpt
-  components/proxyObjInst.xpt
-  components/rdf.xpt
-  components/safebrowsing.xpt
-  components/satchel.xpt
-  components/saxparser.xpt
-  components/search.xpt
-  components/sessionstore.xpt
-  components/shellservice.xpt
-  components/shistory.xpt
-  components/spellchecker.xpt
-  components/storage.xpt
-  components/toolkitprofile.xpt
-  components/toolkitsearch.xpt
-  components/txmgr.xpt
-  components/txtsvc.xpt
-  components/uconv.xpt
-  components/unicharutil.xpt
-  components/update.xpt
-  components/uriloader.xpt
-  components/url-classifier.xpt
-  components/urlformatter.xpt
-  components/webBrowser_core.xpt
-  components/webbrowserpersist.xpt
-  components/webshell_idls.xpt
-  components/websrvcs.xpt
-  components/widget.xpt
-  components/widget_cocoa.xpt
-  components/widget_mac.xpt
-  components/windowds.xpt
-  components/windowwatcher.xpt
-  components/xml-rpc.xpt
-  components/xpcom_base.xpt
-  components/xpcom_components.xpt
-  components/xpcom_ds.xpt
-  components/xpcom_io.xpt
-  components/xpcom_obsolete.xpt
-  components/xpcom_system.xpt
-  components/xpcom_threads.xpt
-  components/xpcom_xpti.xpt
-  components/xpconnect.xpt
-  components/xpinstall.xpt
-  components/xulapp.xpt
-  components/xuldoc.xpt
-  components/xultmpl.xpt
-  components/zipwriter.xpt
-  extensions/inspector@mozilla.org/chrome/chromelist.txt
-  init.d/README
-  libwidget.rsrc
-  plugin-container
-  plugins/Default Plugin.plugin/Contents/Info.plist
-  plugins/Default Plugin.plugin/Contents/MacOS/Default Plugin
-  plugins/Default Plugin.plugin/Contents/PkgInfo
-  plugins/Default Plugin.plugin/Contents/Resources/Default Plugin.rsrc
-  plugins/Default Plugin.plugin/Contents/Resources/English.lproj/InfoPlist.strings
-  plugins/DefaultPlugin.plugin/Contents/Info.plist
-  plugins/DefaultPlugin.plugin/Contents/MacOS/DefaultPlugin
-  plugins/DefaultPlugin.plugin/Contents/Resources/English.lproj/InfoPlist.strings
-  plugins/DefaultPlugin.plugin/Contents/Resources/plugin.png
-  plugins/JavaEmbeddingPlugin.bundle/Contents/Info.plist
-  plugins/JavaEmbeddingPlugin.bundle/Contents/MacOS/JavaEmbeddingPlugin
-  plugins/JavaEmbeddingPlugin.bundle/Contents/MacOS/JavaEmbeddingPlugin.policy
-  plugins/JavaEmbeddingPlugin.bundle/Contents/PkgInfo
-  plugins/JavaEmbeddingPlugin.bundle/Contents/Resources/English.lproj/InfoPlist.strings
-  plugins/JavaEmbeddingPlugin.bundle/Contents/Resources/Java/JavaEmbeddingPlugin.jar
-  plugins/MRJPlugin.plugin/Contents/Info.plist
-  plugins/MRJPlugin.plugin/Contents/MacOS/MRJPlugin
-  plugins/MRJPlugin.plugin/Contents/MacOS/MRJPlugin.jar
-  plugins/MRJPlugin.plugin/Contents/MacOS/MRJPlugin.policy
-  plugins/MRJPlugin.plugin/Contents/MacOS/MRJPlugin.properties
-  plugins/MRJPlugin.plugin/Contents/PkgInfo
-  plugins/MRJPlugin.plugin/Contents/Resources/English.lproj/InfoPlist.strings
-  plugins/MRJPlugin.plugin/Contents/Resources/MRJPlugin.rsrc
-  redo-prebinding.sh
-  res/bloatcycle.html
-  res/cursors/arrowN.tiff
-  res/cursors/arrowS.tiff
-  res/cursors/colResize.tiff
-  res/cursors/help.tiff
-  res/cursors/rowResize.tiff
-  res/cursors/sizeNE.tiff
-  res/cursors/sizeNESW.tiff
-  res/cursors/sizeNS.tiff
-  res/cursors/sizeNW.tiff
-  res/cursors/sizeNWSE.tiff
-  res/cursors/sizeSE.tiff
-  res/cursors/sizeSW.tiff
-  res/cursors/spin1.tiff
-  res/cursors/spin2.tiff
-  res/cursors/spin3.tiff
-  res/cursors/spin4.tiff
-  res/cursors/vtIBeam.tiff
-  res/cursors/zoomIn.tiff
-  res/cursors/zoomOut.tiff
-  res/cursors/CVS/Entries
-  res/cursors/CVS/Repository
-  res/cursors/CVS/Root
-  res/cursors/CVS/Tag
-  res/viewer.properties
-  updater.app/Contents/MacOS/updater.ini
-#endif
-#ifdef XP_UNIX
-  #ifndef XP_MACOSX
-    chrome/icons/default/default.xpm
-    components/libimgicon.so
-    dictionaries/PL.aff
-    dictionaries/PL.dic
-    icons/document.png
-    icons/mozicon16.xpm
-    icons/mozicon50.xpm
-    plugins/libnullplugin.so
-    readme.txt
-  #endif
-#endif
-#ifndef XP_WIN
-  res/fonts/mathfontSymbol.properties
-#endif
-#ifdef XP_WIN
-  components/brwsrcmp.dll
-  components/jsd3250.dll
-  components/nsPostUpdateWin.js
-  js3250.dll
-  mozcpp19.dll
-  mozcrt19.dll
-  #if MOZ_MSVC_REDIST != 1400
-    Microsoft.VC80.CRT.manifest
-    msvcm80.dll
-    msvcp80.dll
-    msvcr80.dll
-  #endif
-  #if MOZ_MSVC_REDIST != 1500
-    Microsoft.VC90.CRT.manifest
-    msvcm90.dll
-    msvcp90.dll
-    msvcr90.dll
-  #endif
-  #if MOZ_MSVC_REDIST != 1600
-    msvcp100.dll
-    msvcr100.dll
-  #endif
-  #if MOZ_MSVC_REDIST != 1700
-    msvcp110.dll
-    msvcr110.dll
-    #ifdef MOZ_METRO
-      vccorlib110.dll
-    #endif
-  #endif
-  #if MOZ_MSVC_REDIST != 1800
-    msvcp120.dll
-    msvcr120.dll
-    #ifdef MOZ_METRO
-      vccorlib120.dll
-    #endif
-  #endif
-  plugins/npnul32.dll
-#endif
-@DLL_PREFIX@xpcom_core@DLL_SUFFIX@
-components/@DLL_PREFIX@jar50@DLL_SUFFIX@
-#ifdef XP_WIN
-  components/xpinstal.dll
-#else
-  components/@DLL_PREFIX@jsd@DLL_SUFFIX@
-  components/@DLL_PREFIX@xpinstall@DLL_SUFFIX@
-#endif
-#ifndef MOZ_UPDATER
-  components/nsUpdateService.js
-  components/nsUpdateServiceStub.js
-#endif
-#Talkback
-#ifdef XP_WIN
-  extensions/talkback@mozilla.org/components/BrandRes.dll
-  extensions/talkback@mozilla.org/components/fullsoft.dll
-  extensions/talkback@mozilla.org/components/master.ini
-  extensions/talkback@mozilla.org/components/talkback-l10n.ini
-  extensions/talkback@mozilla.org/components/talkback.cnt
-  extensions/talkback@mozilla.org/components/talkback.exe
-  extensions/talkback@mozilla.org/components/talkback.hlp
-  extensions/talkback@mozilla.org/InstallDisabled
-#else
-  #ifdef XP_MACOSX
-    extensions/talkback@mozilla.org/components/talkback/master.ini
-    extensions/talkback@mozilla.org/components/talkback/talkback@DLL_SUFFIX@
-    extensions/talkback@mozilla.org/components/talkback/Talkback.app/Contents/Info.plist
-    extensions/talkback@mozilla.org/components/talkback/Talkback.app/Contents/MacOS/Talkback
-    extensions/talkback@mozilla.org/components/talkback/Talkback.app/Contents/pbdevelopment.plist
-    extensions/talkback@mozilla.org/components/talkback/Talkback.app/Contents/PkgInfo
-    extensions/talkback@mozilla.org/components/talkback/Talkback.app/Contents/Resources/delete.tiff
-    extensions/talkback@mozilla.org/components/talkback/Talkback.app/Contents/Resources/disable.tiff
-    extensions/talkback@mozilla.org/components/talkback/Talkback.app/Contents/Resources/enable.tiff
-    extensions/talkback@mozilla.org/components/talkback/Talkback.app/Contents/Resources/English.lproj/ArchivingSettings.nib/classes.nib
-    extensions/talkback@mozilla.org/components/talkback/Talkback.app/Contents/Resources/English.lproj/ArchivingSettings.nib/info.nib
-    extensions/talkback@mozilla.org/components/talkback/Talkback.app/Contents/Resources/English.lproj/ArchivingSettings.nib/objects.nib
-    extensions/talkback@mozilla.org/components/talkback/Talkback.app/Contents/Resources/English.lproj/InfoPlist.strings
-    extensions/talkback@mozilla.org/components/talkback/Talkback.app/Contents/Resources/English.lproj/IntroWizard.nib/classes.nib
-    extensions/talkback@mozilla.org/components/talkback/Talkback.app/Contents/Resources/English.lproj/IntroWizard.nib/info.nib
-    extensions/talkback@mozilla.org/components/talkback/Talkback.app/Contents/Resources/English.lproj/IntroWizard.nib/objects.nib
-    extensions/talkback@mozilla.org/components/talkback/Talkback.app/Contents/Resources/English.lproj/Localizable.strings
-    extensions/talkback@mozilla.org/components/talkback/Talkback.app/Contents/Resources/English.lproj/MainMenu.nib/classes.nib
-    extensions/talkback@mozilla.org/components/talkback/Talkback.app/Contents/Resources/English.lproj/MainMenu.nib/info.nib
-    extensions/talkback@mozilla.org/components/talkback/Talkback.app/Contents/Resources/English.lproj/MainMenu.nib/objects.nib
-    extensions/talkback@mozilla.org/components/talkback/Talkback.app/Contents/Resources/English.lproj/ProxySettings.nib/classes.nib
-    extensions/talkback@mozilla.org/components/talkback/Talkback.app/Contents/Resources/English.lproj/ProxySettings.nib/info.nib
-    extensions/talkback@mozilla.org/components/talkback/Talkback.app/Contents/Resources/English.lproj/ProxySettings.nib/objects.nib
-    extensions/talkback@mozilla.org/components/talkback/Talkback.app/Contents/Resources/English.lproj/SendingSettings.nib/classes.nib
-    extensions/talkback@mozilla.org/components/talkback/Talkback.app/Contents/Resources/English.lproj/SendingSettings.nib/info.nib
-    extensions/talkback@mozilla.org/components/talkback/Talkback.app/Contents/Resources/English.lproj/SendingSettings.nib/objects.nib
-    extensions/talkback@mozilla.org/components/talkback/Talkback.app/Contents/Resources/KeyInfoKeys.plist
-    extensions/talkback@mozilla.org/components/talkback/Talkback.app/Contents/Resources/KeyInfoSections.plist
-    extensions/talkback@mozilla.org/components/talkback/Talkback.app/Contents/Resources/send.tiff
-    extensions/talkback@mozilla.org/components/talkback/Talkback.app/Contents/Resources/sort_ascending.tiff
-    extensions/talkback@mozilla.org/components/talkback/Talkback.app/Contents/Resources/sort_descending.tiff
-    extensions/talkback@mozilla.org/components/talkback/Talkback.app/Contents/Resources/Talkback.icns
-  #else
-    extensions/talkback@mozilla.org/components/talkback/talkback
-    extensions/talkback@mozilla.org/components/talkback/XTalkback.ad
-    extensions/talkback@mozilla.org/components/talkback/master.ini
-    extensions/talkback@mozilla.org/components/talkback/talkback.so
-  #endif
-#endif
-#Remove Talkback files from old location (in case user updates from 1.0.x)
-components/BrandRes.dll
-components/fullsoft.dll
-components/master.ini
-components/qfaservices.dll
-components/qfaservices.xpt
-components/talkback-l10n.ini
-components/talkback.cnt
-components/talkback.exe
-components/talkback.hlp
-components/libqfaservices.so
-components/talkback/master.ini
-components/talkback/talkback
-components/talkback/talkback.so
-components/talkback/XTalkback.ad
-extensions/reporter@mozilla.org/install.rdf
-extensions/reporter@mozilla.org/chrome.manifest
-extensions/reporter@mozilla.org/chrome/reporter.jar
-extensions/reporter@mozilla.org/defaults/preferences/reporter.js
-#Remove Inspector (present from upgrades from Fx2/Fx3b3)
-extensions/inspector@mozilla.org/install.rdf
-extensions/inspector@mozilla.org/components/inspector-cmdline.js
-extensions/inspector@mozilla.org/chrome.manifest
-extensions/inspector@mozilla.org/chrome/inspector.jar
-extensions/inspector@mozilla.org/defaults/preferences/inspector.js
-extensions/inspector@mozilla.org/platform/WINNT/chrome/icons/default/winInspectorMain.ico
-extensions/inspector@mozilla.org/components/inspector.xpt
-extensions/inspector@mozilla.org/components/@DLL_PREFIX@inspector@DLL_SUFFIX@
-extensions/inspector@mozilla.org/chrome/icons/default/winInspectorMain.ico
-components/nsPlacesTransactionsService.js
-components/browserplaces.xpt
-components/nsPlacesDBFlush.js
-#ifndef MOZ_MAINTENANCE_SERVICE
-maintenanceservice.exe
-maintenanceservice_installer.exe
-#endif
-jssubloader/
+res/*
+searchplugins/*
+webapprt/components/
--- a/browser/locales/en-US/chrome/browser/browser.dtd
+++ b/browser/locales/en-US/chrome/browser/browser.dtd
@@ -104,19 +104,18 @@ These should match what Safari and other
 <!ENTITY fullScreenRestore.tooltip "Restore">
 <!ENTITY fullScreenClose.tooltip "Close">
 <!ENTITY fullScreenAutohide.label "Hide Toolbars">
 <!ENTITY fullScreenAutohide.accesskey "H">
 <!ENTITY fullScreenExit.label "Exit Full Screen Mode">
 <!ENTITY fullScreenExit.accesskey "F">
 <!ENTITY fullscreenAllowButton.label "Allow">
 <!ENTITY fullscreenExitButton.label "Deny">
-<!ENTITY fullscreenApproval.value "Allow fullscreen?">
 
-<!ENTITY fullscreenExitHint.value "Press ESC at any time to exit fullscreen.">
+<!ENTITY fullscreenExitHint2.value "Press ESC at any time to exit.">
 <!ENTITY leaveDOMFullScreen.label "Exit Full Screen">
 <!ENTITY leaveDOMFullScreen.accesskey "u">
 
 <!ENTITY closeWindow.label "Close Window">
 <!ENTITY closeWindow.accesskey "d">
 
 <!ENTITY bookmarksMenu.label "Bookmarks">
 <!ENTITY bookmarksMenu.accesskey "B">
@@ -202,16 +201,19 @@ These should match what Safari and other
 <!ENTITY downloadsUnix.commandkey     "y">
 <!ENTITY addons.label                 "Add-ons">
 <!ENTITY addons.accesskey             "A">
 <!ENTITY addons.commandkey            "A">
 
 <!ENTITY webDeveloperMenu.label       "Web Developer">
 <!ENTITY webDeveloperMenu.accesskey   "W">
 
+<!ENTITY devToolsCmd.keycode          "VK_F12">
+<!ENTITY devToolsCmd.keytext          "F12">
+
 <!ENTITY devtoolsConnect.label        "Connect…">
 <!ENTITY devtoolsConnect.accesskey    "e">
 
 <!ENTITY errorConsoleCmd.label        "Error Console">
 <!ENTITY errorConsoleCmd.accesskey    "C">
 
 <!ENTITY remoteWebConsoleCmd.label    "Remote Web Console">
 
@@ -247,16 +249,18 @@ These should match what Safari and other
 
 <!ENTITY devToolbarCloseButton.tooltiptext "Close Developer Toolbar">
 <!ENTITY devToolbarMenu.label              "Developer Toolbar">
 <!ENTITY devToolbarMenu.accesskey          "v">
 <!ENTITY devToolbar.keycode                "VK_F2">
 <!ENTITY devToolbar.keytext                "F2">
 <!ENTITY devToolboxMenuItem.label          "Toggle Tools">
 <!ENTITY devToolboxMenuItem.accesskey      "T">
+<!ENTITY devToolboxMenuItem.keycode        "I">
+<!ENTITY devToolboxMenuItem.keytext        "I">
 
 <!ENTITY devToolbarToolsButton.tooltip     "Toggle developer tools">
 <!ENTITY devToolbarOtherToolsButton.label  "More Tools">
 
 <!ENTITY getMoreDevtoolsCmd.label        "Get More Tools">
 <!ENTITY getMoreDevtoolsCmd.accesskey    "M">
 
 <!ENTITY fileMenu.label         "File"> 
--- a/browser/locales/en-US/chrome/browser/devtools/debugger.dtd
+++ b/browser/locales/en-US/chrome/browser/devtools/debugger.dtd
@@ -129,12 +129,16 @@
 <!-- LOCALIZATION NOTE (debuggerUI.removeWatch): This is the text that
   -  appears in the watch expressions context menu for removing all expressions. -->
 <!ENTITY debuggerUI.removeAllWatch      "Remove all watch expressions">
 <!ENTITY debuggerUI.removeAllWatch.key  "E">
 
 <!-- LOCALIZATION NOTE (debuggerUI.stepping): These are the keycodes that
   -  control the stepping commands in the debugger (continue, step over,
   -  step in and step out). -->
-<!ENTITY debuggerUI.stepping.resume     "VK_F6">
-<!ENTITY debuggerUI.stepping.stepOver   "VK_F7">
-<!ENTITY debuggerUI.stepping.stepIn     "VK_F8">
-<!ENTITY debuggerUI.stepping.stepOut    "VK_F8">
+<!ENTITY debuggerUI.stepping.resume1    "VK_F8">
+<!ENTITY debuggerUI.stepping.resume2    "VK_SLASH">
+<!ENTITY debuggerUI.stepping.stepOver1  "VK_F10">
+<!ENTITY debuggerUI.stepping.stepOver2  "VK_QUOTE">
+<!ENTITY debuggerUI.stepping.stepIn1    "VK_F11">
+<!ENTITY debuggerUI.stepping.stepIn2    "VK_SEMICOLON">
+<!ENTITY debuggerUI.stepping.stepOut1   "VK_F11">
+<!ENTITY debuggerUI.stepping.stepOut2   "VK_SEMICOLON">
--- a/browser/locales/en-US/chrome/browser/devtools/inspector.properties
+++ b/browser/locales/en-US/chrome/browser/devtools/inspector.properties
@@ -30,17 +30,17 @@ debuggerPausedWarning.message=Debugger i
 # This menu appears in the Infobar (on top of the highlighted node) once
 # the node is selected.
 nodeMenu.tooltiptext=Node operations
 
 
 # LOCALIZATION NOTE (inspector.*)
 # Used for the menuitem in the tool menu
 inspector.label=Inspector
-inspector.commandkey=I
+inspector.commandkey=C
 inspector.accesskey=I
 
 # LOCALIZATION NOTE (markupView.more.*)
 # When there are too many nodes to load at once, we will offer to
 # show all the nodes.
 markupView.more.showing=Some nodes were hidden.
 markupView.more.showAll=Show All %S Nodes
 inspector.tooltip=DOM and Style Inspector
--- a/browser/metro/base/content/appbar.js
+++ b/browser/metro/base/content/appbar.js
@@ -34,17 +34,17 @@ var Appbar = {
       case 'MozAppbarShowing':
         this.update();
         break;
 
       case 'MozAppbarDismissing':
         if (this.activeTileset && ('isBound' in this.activeTileset)) {
           this.activeTileset.clearSelection();
         }
-        this.clearContextualActions();
+        this._clearContextualActions();
         this.activeTileset = null;
         break;
 
       case 'MozContextActionsChange':
         let actions = aEvent.actions;
         let setName = aEvent.target.contextSetName;
         // could transition in old, new buttons?
         this.showContextualActions(actions, setName);
@@ -169,18 +169,16 @@ var Appbar = {
   },
 
   showContextualActions: function(aVerbs, aSetName) {
     // When the appbar is not visible, we want the icons to refresh right away
     let immediate = !Elements.contextappbar.isShowing;
 
     if (aVerbs.length) {
       Elements.contextappbar.show();
-    } else {
-      Elements.contextappbar.hide();
     }
 
     // Look up all of the buttons for the verbs that should be visible.
     let idsToVisibleVerbs = new Map();
     for (let verb of aVerbs) {
       let id = verb + "-selected-button";
       if (!document.getElementById(id)) {
         throw new Error("Appbar.showContextualActions: no button for " + verb);
@@ -222,17 +220,17 @@ var Appbar = {
         yield Util.transitionElementVisibility(toHide, false);
       }
       if (toShow.length) {
         yield Util.transitionElementVisibility(toShow, true);
       }
     });
   },
 
-  clearContextualActions: function() {
+  _clearContextualActions: function() {
     this.showContextualActions([]);
   },
 
   _updateContextualActionLabel: function(aButton, aVerb, aSetName) {
     // True if the action's label string contains the set name and
     // thus has to be selected based on the list passed in.
     let usesSetName = aButton.hasAttribute("label-uses-set-name");
     let name = "contextAppbar2." + aVerb + (usesSetName ? "." + aSetName : "");
--- a/browser/metro/base/content/bindings/appbar.xml
+++ b/browser/metro/base/content/bindings/appbar.xml
@@ -68,10 +68,15 @@
               this.dismiss();
             } else {
               this.show();
             }
           ]]>
         </body>
       </method>
     </implementation>
+
+    <handlers>
+      <!-- Work around for bug 835175 -->
+      <handler event="click">false;</handler>
+    </handlers>
   </binding>
 </bindings>
--- a/browser/metro/base/content/bindings/flyoutpanel.xml
+++ b/browser/metro/base/content/bindings/flyoutpanel.xml
@@ -94,10 +94,15 @@
         </body>
       </method>
 
       <field name="anonScrollBox" readonly="true"><![CDATA[
         // Expose the anyonymous scrollbox so ScrollUtils.getScrollboxFromElement can find it.
         document.getAnonymousElementByAttribute(this, "class", "flyoutpanel-contents");
       ]]></field>
     </implementation>
+
+    <handlers>
+      <!-- Work around for bug 835175 -->
+      <handler event="click">false;</handler>
+    </handlers>
   </binding>
 </bindings>
--- a/browser/metro/base/content/browser.xul
+++ b/browser/metro/base/content/browser.xul
@@ -176,17 +176,18 @@
   </keyset>
 
   <stack id="stack" flex="1">
     <observes element="bcast_urlbarState" attribute="*"/>
     <!-- Page Area -->
     <vbox id="page">
       <vbox id="tray" class="tray-toolbar" observes="bcast_windowState" >
         <!-- Tabs -->
-        <hbox id="tabs-container" observes="bcast_windowState">
+        <!-- onclick handler to work around bug 837242 -->
+        <hbox id="tabs-container" observes="bcast_windowState" onclick="void(0);">
           <box id="tabs" flex="1"
                 observes="bcast_preciseInput"
                 onselect="BrowserUI.selectTabAndDismiss(this);"
                 onclosetab="BrowserUI.closeTab(this);"/>
           <vbox id="tabs-controls">
             <toolbarbutton id="newtab-button" command="cmd_newTab" label="&newtab.label;"/>
           </vbox>
         </hbox>
@@ -237,17 +238,18 @@
 
       <!-- Content viewport -->
       <stack id="content-viewport">
         <deck id="browsers" flex="1" observes="bcast_preciseInput"/>
         <box id="vertical-scroller" class="scroller" orient="vertical" end="0" top="0"/>
         <box id="horizontal-scroller" class="scroller" orient="horizontal" left="0" bottom="0"/>
 
         <!-- Content touch selection overlay -->
-        <box class="selection-overlay-hidden" id="content-selection-overlay"/>
+        <!-- onclick addresses dom bug 835175 -->
+        <box onclick="false" class="selection-overlay-hidden" id="content-selection-overlay"/>
       </stack>
     </vbox>
 
     <html:div id="overlay-back" class="overlay-button"
               observes="cmd_back"></html:div>
     <html:div id="overlay-plus" class="overlay-button"
               observes="cmd_back"></html:div>
 
@@ -731,19 +733,21 @@
             <radio id="prefs-dnt-nopref" label="&doNotTrack.options.noPreference;" value="-1"/>
             <radio id="prefs-dnt-oktrack" label="&doNotTrack.options.trackingOkay;" value="0"/>
           </radiogroup>
         </setting>
       </settings>
     </flyoutpanel>
 
     <!-- Chrome touch selection overlay -->
-    <box class="selection-overlay-hidden" id="chrome-selection-overlay"/>
+    <!-- onclick addresses dom bug 835175 -->
+    <box onclick="false" class="selection-overlay-hidden" id="chrome-selection-overlay"/>
 
     <box onclick="event.stopPropagation();" id="context-container" class="menu-container" hidden="true">
+      <!-- onclick is dom bug 835175 -->
       <vbox id="context-popup" class="menu-popup">
         <richlistbox id="context-commands" bindingType="contextmenu" flex="1">
           <!-- priority="low" items are hidden by default when a context is being displayed
                for two or more media types. (e.g. a linked image) -->
           <!-- content types preceeded by '!' act as exclusion rules, the menu item will not
                be displayed if the content type is present. -->
           <!-- Note the order of richlistitem here is important as it is reflected in the
                menu itself. -->
new file mode 100644
--- /dev/null
+++ b/browser/metro/base/content/pages/aboutAddons.xhtml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html [
+  <!ENTITY % htmlDTD PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "DTD/xhtml1-strict.dtd">
+  %htmlDTD;
+  <!ENTITY % brandDTD SYSTEM "chrome://branding/locale/brand.dtd">
+  %brandDTD;
+  <!ENTITY % aboutAddonsDTD SYSTEM "chrome://browser/locale/aboutAddons.dtd">
+  %aboutAddonsDTD;
+]>
+
+<!-- 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/. -->
+<html xmlns="http://www.w3.org/1999/xhtml">
+
+<head>
+  <title> &aboutAddons.title; </title>
+  <link rel="stylesheet" href="chrome://browser/skin/aboutAddons.css" type="text/css"/>
+</head>
+
+<body>
+  <div id="fox">
+    <div id="floatingTextBox">
+      <div id="aboutAddonsTextTitle">
+        &aboutAddons.messageTitle;
+      </div>
+      <div id="aboutAddonsTextBody">
+        &aboutAddons.message;
+        &aboutAddons.goBackToStart;
+        <a href="about:start">&aboutAddons.startPageLinkTitle;</a>
+      </div>
+    </div>
+  </div>
+</body>
+</html>
--- a/browser/metro/base/jar.mn
+++ b/browser/metro/base/jar.mn
@@ -5,16 +5,17 @@
 
 chrome.jar:
 % content browser %content/
 
   content/aboutCertError.xhtml                 (content/pages/aboutCertError.xhtml)
   content/aboutRights.xhtml                    (content/pages/aboutRights.xhtml)
   content/blockedSite.xhtml                    (content/pages/blockedSite.xhtml)
   content/netError.xhtml                       (content/pages/netError.xhtml)
+  content/aboutAddons.xhtml                    (content/pages/aboutAddons.xhtml)
 
   content/bindings/bindings.xml                (content/bindings/bindings.xml)
   content/bindings/tabs.xml                    (content/bindings/tabs.xml)
   content/bindings/toggleswitch.xml            (content/bindings/toggleswitch.xml)
   content/bindings/browser.xml                 (content/bindings/browser.xml)
   content/bindings/browser.js                  (content/bindings/browser.js)
   content/bindings/console.xml                 (content/bindings/console.xml)
   content/bindings/dialog.xml                  (content/bindings/dialog.xml)
@@ -96,8 +97,9 @@ chrome.jar:
   content/RemoteTabs.js                        (content/RemoteTabs.js)
 #endif
   content/NavButtonSlider.js                   (content/NavButtonSlider.js)
   content/ContextUI.js                         (content/ContextUI.js)
   content/apzc.js                              (content/apzc.js)
 
 % override chrome://global/content/config.xul chrome://browser/content/config.xul
 % override chrome://global/content/netError.xhtml chrome://browser/content/netError.xhtml
+% override chrome://mozapps/content/extensions/extensions.xul chrome://browser/content/aboutAddons.xhtml
--- a/browser/metro/base/tests/mochitest/Makefile.in
+++ b/browser/metro/base/tests/mochitest/Makefile.in
@@ -11,28 +11,27 @@ relativesrcdir  = @relativesrcdir@
 include $(DEPTH)/config/autoconf.mk
 
 # Disabled for intermittent failures 
 # Bug 880739
 #  browser_context_menu_tests.js \
 #  browser_context_menu_tests_01.html \
 #  browser_context_menu_tests_02.html \
 #  browser_context_menu_tests_03.html \
-# Bug 897175
-#  browser_findbar.js \
-#  browser_findbar.html \
 
 MOCHITEST_METRO_FILES = \
   head.js \
   browser_urlbar.js \
   browser_bookmarks.js \
   browser_canonizeURL.js \
   browser_circular_progress_indicator.js \
   browser_context_ui.js \
   browser_downloads.js \
+  browser_findbar.js \
+  browser_findbar.html \
   browser_history.js \
   browser_onscreen_keyboard.js \
   browser_onscreen_keyboard.html \
   browser_prefs_ui.js \
   browser_progress_indicator.xul \
   browser_remotetabs.js \
   browser_tabs.js \
   browser_test.js \
--- a/browser/metro/base/tests/mochitest/browser_findbar.js
+++ b/browser/metro/base/tests/mochitest/browser_findbar.js
@@ -42,21 +42,23 @@ gTests.push({
     is(ContextUI.navbarVisible, false, "Navbar is hidden by default");
     is(Elements.findbar.isShowing, false, "Find bar is hidden by default");
 
     yield showNavBar();
     is(ContextUI.navbarVisible, true, "Navbar is visible");
     is(Elements.findbar.isShowing, false, "Find bar is still hidden");
 
     EventUtils.synthesizeKey("f", { accelKey: true });
-    yield waitForEvent(Elements.navbar, "transitionend");
+    yield Promise.all(waitForEvent(Elements.navbar, "transitionend"),
+                      waitForEvent(Elements.findbar, "transitionend"));
     is(ContextUI.navbarVisible, false, "Navbar is hidden");
     is(Elements.findbar.isShowing, true, "Findbar is visible");
 
-    yield showNavBar();
+    yield Promise.all(showNavBar(),
+                      waitForEvent(Elements.findbar, "transitionend"));
     is(ContextUI.navbarVisible, true, "Navbar is visible again");
     is(Elements.findbar.isShowing, false, "Find bar is hidden again");
 
     Browser.closeTab(tab);
   }
 });
 
 
new file mode 100644
--- /dev/null
+++ b/browser/metro/locales/en-US/chrome/aboutAddons.dtd
@@ -0,0 +1,13 @@
+<!-- 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 % brandDTD
+     SYSTEM "chrome://branding/locale/brand.dtd">
+   %brandDTD;
+
+<!ENTITY aboutAddons.title              "Addons are a Work In Progress">
+<!ENTITY aboutAddons.messageTitle       "Uh-Oh!">
+<!ENTITY aboutAddons.message            "Sorry, &brandShortName; is busy working on supporting Add-ons for you!">
+<!ENTITY aboutAddons.goBackToStart      "Go back to the ">
+<!ENTITY aboutAddons.startPageLinkTitle "&brandShortName; Start Page.">
--- a/browser/metro/locales/jar.mn
+++ b/browser/metro/locales/jar.mn
@@ -18,16 +18,17 @@
   locale/browser/checkbox.dtd             (%chrome/checkbox.dtd)
   locale/browser/sync.dtd                 (%chrome/sync.dtd)
   locale/browser/sync.properties          (%chrome/sync.properties)
   locale/browser/passwordmgr.properties   (%chrome/passwordmgr.properties)
   locale/browser/prompt.dtd               (%chrome/prompt.dtd)
   locale/browser/phishing.dtd             (%chrome/phishing.dtd)
   locale/browser/crashprompt.dtd          (%chrome/crashprompt.dtd)
   locale/browser/crashprompt.properties   (%chrome/crashprompt.properties)
+  locale/browser/aboutAddons.dtd          (%chrome/aboutAddons.dtd)
 
 @AB_CD@.jar:
 % locale browser @AB_CD@ %locale/browser/
   locale/browser/bookmarks.json           (bookmarks.json)
 
 #
 # Browser jar resources
 #
new file mode 100644
--- /dev/null
+++ b/browser/metro/theme/aboutAddons.css
@@ -0,0 +1,52 @@
+/* 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/. */
+
+html, body {
+  height: 100%;
+  padding: 0;
+  margin: 0;
+}
+
+body {
+  display: flex;
+}
+
+#aboutAddonsTextTitle {
+  font-weight: bold;
+}
+
+#floatingTextBox {
+  flex: 1;
+  
+  position: relative;
+  top: 20%;
+  left: 60%;
+
+  width: 375px;
+  padding: 20px;
+  font-family: "Segoe UI", sans-serif;
+  font-size: 25px;
+  text-align: left;
+  word-wrap: normal;
+}
+
+#fox {
+  flex: 1;
+  background-image:url('chrome://browser/skin/images/aboutAddonsBackground.png'), url('chrome://browser/skin/images/aboutAddonsBackgroundFillSlice.png');
+  background-size: contain;
+  background-position: bottom center;
+  background-repeat: no-repeat, repeat-x;
+  background-color: rgb(230, 230, 230); /*color hand sampled from image*/
+
+}
+
+/* Snapped-view variation */
+@media (max-width: 330px) {
+  #floatingTextBox {
+    top: 20%;
+    left: 5%;
+    width: 90%;
+    padding: 0;
+  }
+}
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..5f265200dd14b7f0fc754219f5805fdbbdb2cce2
GIT binary patch
literal 43723
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
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..17000f0578ad1f7b8ed2f867f7815a10c25798e1
GIT binary patch
literal 2810
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
M07*qoM6N<$g3jPXMgRZ+
--- a/browser/metro/theme/jar.mn
+++ b/browser/metro/theme/jar.mn
@@ -2,16 +2,17 @@
 # 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/.
 
 
 chrome.jar:
 % skin browser classic/1.0 %skin/
   skin/aboutPage.css                        (aboutPage.css)
+  skin/aboutAddons.css                      (aboutAddons.css)
   skin/about.css                            (about.css)
 * skin/flyoutpanel.css                      (flyoutpanel.css)
 * skin/cssthrobber.css                      (cssthrobber.css)
 * skin/browser.css                          (browser.css)
 * skin/content.css                          (content.css)
   skin/config.css                           (config.css)
 * skin/platform.css                         (platform.css)
 * skin/tiles.css                            (tiles.css)
@@ -55,16 +56,18 @@ chrome.jar:
   skin/images/identity-icons-https-ev.png   (images/identity-icons-https-ev.png)
   skin/images/identity-icons-https-mixed.png  (images/identity-icons-https-mixed.png)
   skin/images/identity-icons-https.png      (images/identity-icons-https.png)
   skin/images/infobar-close.png             (images/infobar-close.png)
   skin/images/infobar-geolocation.png       (images/infobar-geolocation.png)
   skin/images/infobar-key.png               (images/infobar-key.png)
   skin/images/infobar-popup.png             (images/infobar-popup.png)
   skin/images/firefox-watermark.png         (images/firefox-watermark.png)
+  skin/images/aboutAddonsBackground.png     (images/aboutAddonsBackground.png)
+  skin/images/aboutAddonsBackgroundFillSlice.png     (images/aboutAddonsBackgroundFillSlice.png)
   skin/images/flyout-back-button.png        (images/flyout-back-button.png)
   skin/images/about-footer.png              (images/about-footer.png)
   skin/images/button-bg.png                 (images/button-bg.png)
   skin/images/arrowleft-16.png              (images/arrowleft-16.png)
   skin/images/arrowright-16.png             (images/arrowright-16.png)
   skin/images/arrowup-16.png                (images/arrowup-16.png)
   skin/images/arrowdown-16.png              (images/arrowdown-16.png)
   skin/images/arrowleftdark-16.png          (images/arrowleftdark-16.png)
--- a/browser/themes/linux/browser.css
+++ b/browser/themes/linux/browser.css
@@ -2028,19 +2028,19 @@ toolbar[mode="text"] toolbarbutton.chevr
 .statuspanel-label:-moz-locale-dir(rtl):not([mirror]),
 .statuspanel-label:-moz-locale-dir(ltr)[mirror] {
   border-left-style: solid;
   border-top-left-radius: .3em;
   margin-left: 1em;
 }
 
 #full-screen-warning-message {
-  background-color: hsl(0,0%,15%);
+  background-image: url("chrome://browser/skin/fullscreen-darknoise.png");
   color: white;
-  border-radius: 8px;
+  border-radius: 4px;
   margin-top: 30px;
   padding: 30px 50px;
   box-shadow: 0 0 2px white;
 }
 
 #full-screen-warning-container[obscure-browser] {
   background-color: rgba(0,0,0,0.3);
 }
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..5c33e24d4c1b123c46d6e89e0adec137bfd4da0b
GIT binary patch
literal 3050
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
--- a/browser/themes/linux/jar.mn
+++ b/browser/themes/linux/jar.mn
@@ -17,16 +17,17 @@ browser.jar:
   skin/classic/browser/aboutSocialError.css
 #ifdef MOZ_SERVICES_SYNC
   skin/classic/browser/aboutSyncTabs.css
 #endif
   skin/classic/browser/actionicon-tab.png
 * skin/classic/browser/browser.css
   skin/classic/browser/click-to-play-warning-stripes.png
 * skin/classic/browser/engineManager.css
+  skin/classic/browser/fullscreen-darknoise.png
   skin/classic/browser/Geolocation-16.png
   skin/classic/browser/Geolocation-64.png
   skin/classic/browser/Go-arrow.png
   skin/classic/browser/identity.png
   skin/classic/browser/identity-icons-generic.png
   skin/classic/browser/identity-icons-https.png
   skin/classic/browser/identity-icons-https-ev.png
   skin/classic/browser/identity-icons-https-mixed-active.png
--- a/browser/themes/osx/browser.css
+++ b/browser/themes/osx/browser.css
@@ -3621,19 +3621,19 @@ toolbarbutton.chevron > .toolbarbutton-m
      * above. The rules combined force the top 22px of the background image to
      * be hidden, so there image doesn't jump around with the loss of the titlebar */
     padding-top: 11px;
     background-position: right -11px;
   }
 }
 
 #full-screen-warning-message {
-  background-color: hsl(0,0%,15%);
+  background-image: url("chrome://browser/skin/fullscreen-darknoise.png");
   color: white;
-  border-radius: 8px;
+  border-radius: 4px;
   margin-top: 30px;
   padding: 30px 50px;
   box-shadow: 0 0 2px white;
 }
 
 #full-screen-warning-container[obscure-browser] {
   background-color: rgba(0,0,0,0.3);
 }
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..5c33e24d4c1b123c46d6e89e0adec137bfd4da0b
GIT binary patch
literal 3050
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
--- a/browser/themes/osx/jar.mn
+++ b/browser/themes/osx/jar.mn
@@ -17,16 +17,17 @@ browser.jar:
 #ifdef MOZ_SERVICES_SYNC
   skin/classic/browser/aboutSyncTabs.css
 #endif
   skin/classic/browser/actionicon-tab.png
   skin/classic/browser/actionicon-tab@2x.png
 * skin/classic/browser/browser.css                          (browser.css)
   skin/classic/browser/click-to-play-warning-stripes.png
 * skin/classic/browser/engineManager.css                    (engineManager.css)
+  skin/classic/browser/fullscreen-darknoise.png
   skin/classic/browser/Geolocation-16.png
   skin/classic/browser/Geolocation-16@2x.png
   skin/classic/browser/Geolocation-64.png
   skin/classic/browser/Geolocation-64@2x.png
   skin/classic/browser/home.png
   skin/classic/browser/identity.png
   skin/classic/browser/identity@2x.png
   skin/classic/browser/identity-icons-generic.png
--- a/browser/themes/shared/devtools/webconsole.inc.css
+++ b/browser/themes/shared/devtools/webconsole.inc.css
@@ -267,8 +267,22 @@
 
 .webconsole-msg-security.webconsole-msg-error {
   -moz-image-region: rect(32px, 16px, 40px, 8px);
 }
 
 .webconsole-msg-security.webconsole-msg-warn {
   -moz-image-region: rect(32px, 24px, 40px, 16px);
 }
+
+.navigation-marker {
+  color: #aaa;
+  background: linear-gradient(#fff, #bbb, #fff) no-repeat left 50%;
+  background-size: 100% 2px;
+  -moz-margin-start: 3px;
+  -moz-margin-end: 6px;
+  font-size: 0.9em;
+}
+
+.navigation-marker .url {
+  background: #fff;
+  -moz-padding-end: 6px;
+}
--- a/browser/themes/windows/browser.css
+++ b/browser/themes/windows/browser.css
@@ -2778,19 +2778,19 @@ toolbarbutton.bookmark-item[dragover="tr
   border-left-style: solid;
   /* disabled for triggering grayscale AA (bug 659213)
   border-top-left-radius: .3em;
   */
   margin-left: 1em;
 }
 
 #full-screen-warning-message {
-  background-color: hsl(0,0%,15%);
+  background-image: url("chrome://browser/skin/fullscreen-darknoise.png");
   color: white;
-  border-radius: 8px;
+  border-radius: 4px;
   margin-top: 30px;
   padding: 30px 50px;
   box-shadow: 0 0 2px white;
 }
 
 #full-screen-warning-container[obscure-browser] {
   background-color: rgba(0,0,0,0.3);
 }
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..5c33e24d4c1b123c46d6e89e0adec137bfd4da0b
GIT binary patch
literal 3050
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
--- a/browser/themes/windows/jar.mn
+++ b/browser/themes/windows/jar.mn
@@ -21,16 +21,17 @@ browser.jar:
         skin/classic/browser/aboutSyncTabs.css
 #endif
         skin/classic/browser/actionicon-tab.png
         skin/classic/browser/appmenu-icons.png
         skin/classic/browser/appmenu-dropmarker.png
 *       skin/classic/browser/browser.css
         skin/classic/browser/click-to-play-warning-stripes.png
 *       skin/classic/browser/engineManager.css
+        skin/classic/browser/fullscreen-darknoise.png
         skin/classic/browser/Geolocation-16.png
         skin/classic/browser/Geolocation-64.png
         skin/classic/browser/Info.png
         skin/classic/browser/identity.png
         skin/classic/browser/identity-icons-generic.png
         skin/classic/browser/identity-icons-https.png
         skin/classic/browser/identity-icons-https-ev.png
         skin/classic/browser/identity-icons-https-mixed-active.png
@@ -278,16 +279,17 @@ browser.jar:
         skin/classic/aero/browser/aboutSyncTabs.css
 #endif
         skin/classic/aero/browser/actionicon-tab.png
         skin/classic/aero/browser/appmenu-dropmarker.png
         skin/classic/aero/browser/appmenu-icons.png
 *       skin/classic/aero/browser/browser.css                        (browser-aero.css)
         skin/classic/aero/browser/click-to-play-warning-stripes.png
 *       skin/classic/aero/browser/engineManager.css
+        skin/classic/aero/browser/fullscreen-darknoise.png
         skin/classic/aero/browser/Geolocation-16.png
         skin/classic/aero/browser/Geolocation-64.png
         skin/classic/aero/browser/Info.png                           (Info-aero.png)
         skin/classic/aero/browser/identity.png                       (identity-aero.png)
         skin/classic/aero/browser/identity-icons-generic.png
         skin/classic/aero/browser/identity-icons-https.png
         skin/classic/aero/browser/identity-icons-https-ev.png
         skin/classic/aero/browser/identity-icons-https-mixed-active.png
--- a/config/createprecomplete.py
+++ b/config/createprecomplete.py
@@ -6,38 +6,33 @@
 # longer present in a complete update. The current working directory is used for
 # the location to enumerate and to create the precomplete file.
 
 import sys
 import os
 
 def get_build_entries(root_path):
     """ Iterates through the root_path, creating a list for each file and
-        directory. Excludes any path starting with extensions or distribution
-        and paths ending with channel-prefs.js.
+        directory. Excludes any file paths ending with channel-prefs.js.
     """
     rel_file_path_set = set()
     rel_dir_path_set = set()
     for root, dirs, files in os.walk(root_path):
         for file_name in files:
             parent_dir_rel_path = root[len(root_path)+1:]
             rel_path_file = os.path.join(parent_dir_rel_path, file_name)
             rel_path_file = rel_path_file.replace("\\", "/")
-            if not (rel_path_file.startswith("distribution/") or
-                    rel_path_file.startswith("extensions/") or
-                    rel_path_file.endswith("channel-prefs.js")):
+            if not (rel_path_file.endswith("channel-prefs.js")):
                 rel_file_path_set.add(rel_path_file)
 
         for dir_name in dirs:
             parent_dir_rel_path = root[len(root_path)+1:]
             rel_path_dir = os.path.join(parent_dir_rel_path, dir_name)
             rel_path_dir = rel_path_dir.replace("\\", "/")+"/"
-            if not (rel_path_dir.startswith("distribution/") or
-                    rel_path_dir.startswith("extensions/")):
-                rel_dir_path_set.add(rel_path_dir)
+            rel_dir_path_set.add(rel_path_dir)
 
     rel_file_path_list = list(rel_file_path_set)
     rel_file_path_list.sort(reverse=True)
     rel_dir_path_list = list(rel_dir_path_set)
     rel_dir_path_list.sort(reverse=True)
 
     return rel_file_path_list, rel_dir_path_list
 
--- a/configure.in
+++ b/configure.in
@@ -4202,17 +4202,16 @@ MOZ_DISABLE_CRYPTOLEGACY=
 NSS_DISABLE_DBM=
 NECKO_COOKIES=1
 NECKO_PROTOCOLS_DEFAULT="about data file ftp http res viewsource websocket wyciwyg device"
 USE_ARM_KUSER=
 BUILD_CTYPES=1
 MOZ_USE_NATIVE_POPUP_WINDOWS=
 MOZ_ANDROID_HISTORY=
 MOZ_WEBSMS_BACKEND=
-MOZ_ANDROID_WALLPAPER=
 MOZ_ANDROID_BEAM=
 ACCESSIBILITY=1
 MOZ_TIME_MANAGER=
 MOZ_PAY=
 MOZ_AUDIO_CHANNEL_MANAGER=
 NSS_NO_LIBPKIX=
 
 case "$target_os" in
@@ -5162,23 +5161,16 @@ MOZ_ARG_DISABLE_BOOL(websms-backend,
     MOZ_WEBSMS_BACKEND=,
     MOZ_WEBSMS_BACKEND=1)
 
 if test -n "$MOZ_WEBSMS_BACKEND"; then
     AC_DEFINE(MOZ_WEBSMS_BACKEND)
 fi
 
 dnl ========================================================
-dnl = Enable SET_WALLPAPER permission on Android
-dnl ========================================================
-if test -n "$MOZ_ANDROID_WALLPAPER"; then
-    AC_DEFINE(MOZ_ANDROID_WALLPAPER)
-fi
-
-dnl ========================================================
 dnl = Enable NFC permission on Android
 dnl ========================================================
 if test -n "$MOZ_ANDROID_BEAM"; then
     AC_DEFINE(MOZ_ANDROID_BEAM)
 fi
 
 dnl ========================================================
 dnl = JS Debugger XPCOM component (js/jsd)
@@ -8607,17 +8599,16 @@ AC_SUBST(MOZ_DIRECTX_SDK_PATH)
 AC_SUBST(MOZ_DIRECTX_SDK_CPU_SUFFIX)
 AC_SUBST(MOZ_D3DX9_VERSION)
 AC_SUBST(MOZ_D3DCOMPILER_CAB)
 AC_SUBST(MOZ_D3DCOMPILER_DLL)
 AC_SUBST(MOZ_METRO)
 
 AC_SUBST(MOZ_ANDROID_HISTORY)
 AC_SUBST(MOZ_WEBSMS_BACKEND)
-AC_SUBST(MOZ_ANDROID_WALLPAPER)
 AC_SUBST(MOZ_ANDROID_BEAM)
 AC_SUBST(ENABLE_STRIP)
 AC_SUBST(PKG_SKIP_STRIP)
 AC_SUBST(STRIP_FLAGS)
 AC_SUBST(USE_ELF_DYNSTR_GC)
 AC_SUBST(USE_ELF_HACK)
 AC_SUBST(INCREMENTAL_LINKER)
 AC_SUBST(MOZ_COMPONENTS_VERSION_SCRIPT_LDFLAGS)
--- a/mobile/android/base/ActivityHandlerHelper.java
+++ b/mobile/android/base/ActivityHandlerHelper.java
@@ -94,16 +94,20 @@ public class ActivityHandlerHelper imple
     public int makeRequestCodeForAwesomebar() {
         return mActivityResultHandlerMap.put(mAwesomebarResultHandler);
     }
 
     public int makeRequestCode(ActivityResultHandler aHandler) {
         return mActivityResultHandlerMap.put(aHandler);
     }
 
+    public void startIntentForActivity (Activity activity, Intent intent, ActivityResultHandler activityResultHandler) {
+        activity.startActivityForResult(intent, mActivityResultHandlerMap.put(activityResultHandler));
+    }
+
     private int addIntentActivitiesToList(Context context, Intent intent, ArrayList<Prompt.PromptListItem> items, ArrayList<Intent> aIntents) {
         PackageManager pm = context.getPackageManager();
         List<ResolveInfo> lri = pm.queryIntentActivityOptions(GeckoAppShell.getGeckoInterface().getActivity().getComponentName(), null, intent, 0);
 
         if (lri == null) {
             return 0;
         }
 
--- a/mobile/android/base/AndroidManifest.xml.in
+++ b/mobile/android/base/AndroidManifest.xml.in
@@ -23,19 +23,16 @@
     <uses-permission android:name="android.permission.INTERNET"/>
     <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
     <uses-permission android:name="com.android.launcher.permission.INSTALL_SHORTCUT"/>
     <uses-permission android:name="com.android.launcher.permission.UNINSTALL_SHORTCUT"/>
     <uses-permission android:name="com.android.browser.permission.READ_HISTORY_BOOKMARKS"/>
 
     <uses-permission android:name="android.permission.WAKE_LOCK"/>
     <uses-permission android:name="android.permission.VIBRATE"/>
-#ifdef MOZ_ANDROID_WALLPAPER
-    <uses-permission android:name="android.permission.SET_WALLPAPER"/>
-#endif
     <uses-permission android:name="@ANDROID_PACKAGE_NAME@.permissions.PASSWORD_PROVIDER"/>
     <uses-permission android:name="@ANDROID_PACKAGE_NAME@.permissions.BROWSER_PROVIDER"/>
     <uses-permission android:name="@ANDROID_PACKAGE_NAME@.permissions.FORMHISTORY_PROVIDER"/>
 
 #ifdef MOZ_WEBSMS_BACKEND
     <!-- WebSMS -->
     <uses-permission android:name="android.permission.SEND_SMS"/>
     <uses-permission android:name="android.permission.RECEIVE_SMS"/>
--- a/mobile/android/base/BrowserApp.java
+++ b/mobile/android/base/BrowserApp.java
@@ -1639,18 +1639,18 @@ abstract public class BrowserApp extends
         Tab tab = Tabs.getInstance().getSelectedTab();
         MenuItem bookmark = aMenu.findItem(R.id.bookmark);
         MenuItem forward = aMenu.findItem(R.id.forward);
         MenuItem share = aMenu.findItem(R.id.share);
         MenuItem saveAsPDF = aMenu.findItem(R.id.save_as_pdf);
         MenuItem charEncoding = aMenu.findItem(R.id.char_encoding);
         MenuItem findInPage = aMenu.findItem(R.id.find_in_page);
         MenuItem desktopMode = aMenu.findItem(R.id.desktop_mode);
-        MenuItem enterGuestMode = aMenu.findItem(R.id.enter_guest_mode);
-        MenuItem exitGuestMode = aMenu.findItem(R.id.exit_guest_mode);
+        MenuItem enterGuestMode = aMenu.findItem(R.id.new_guest_session);
+        MenuItem exitGuestMode = aMenu.findItem(R.id.exit_guest_session);
 
         // Only show the "Quit" menu item on pre-ICS or television devices.
         // In ICS+, it's easy to kill an app through the task switcher.
         aMenu.findItem(R.id.quit).setVisible(Build.VERSION.SDK_INT < 14 || HardwareUtils.isTelevision());
 
         if (tab == null || tab.getURL() == null) {
             bookmark.setEnabled(false);
             forward.setEnabled(false);
@@ -1795,20 +1795,20 @@ abstract public class BrowserApp extends
                 GeckoAppShell.sendEventToGecko(GeckoEvent.createBroadcastEvent("DesktopMode:Change", args.toString()));
                 return true;
             case R.id.new_tab:
                 addTab();
                 return true;
             case R.id.new_private_tab:
                 addPrivateTab();
                 return true;
-            case R.id.enter_guest_mode:
+            case R.id.new_guest_session:
                 showGuestModeDialog(GuestModeDialog.ENTERING);
                 return true;
-            case R.id.exit_guest_mode:
+            case R.id.exit_guest_session:
                 showGuestModeDialog(GuestModeDialog.LEAVING);
                 return true;
             default:
                 return super.onOptionsItemSelected(item);
         }
     }
 
     private void showGuestModeDialog(final GuestModeDialog type) {
@@ -1830,28 +1830,28 @@ abstract public class BrowserApp extends
                 } catch(JSONException ex) {
                     Log.e(LOGTAG, "Exception reading guest mode prompt result", ex);
                 }
             }
         });
 
         Resources res = getResources();
         ps.setButtons(new String[] {
-            res.getString(R.string.guest_mode_dialog_continue),
-            res.getString(R.string.guest_mode_dialog_cancel)
+            res.getString(R.string.guest_session_dialog_continue),
+            res.getString(R.string.guest_session_dialog_cancel)
         });
 
         int titleString = 0;
         int msgString = 0;
         if (type == GuestModeDialog.ENTERING) {
-            titleString = R.string.guest_mode_enter_title;
-            msgString = R.string.guest_mode_enter_text;
+            titleString = R.string.new_guest_session_title;
+            msgString = R.string.new_guest_session_text;
         } else {
-            titleString = R.string.guest_mode_leave_title;
-            msgString = R.string.guest_mode_leave_text;
+            titleString = R.string.exit_guest_session_title;
+            msgString = R.string.exit_guest_session_text;
         }
 
         ps.show(res.getString(titleString), res.getString(msgString), null, false);
     }
 
     /**
      * This will detect if the key pressed is back. If so, will show the history.
      */
--- a/mobile/android/base/GeckoApp.java
+++ b/mobile/android/base/GeckoApp.java
@@ -14,16 +14,17 @@ import org.mozilla.gecko.gfx.LayerView;
 import org.mozilla.gecko.gfx.PluginLayer;
 import org.mozilla.gecko.menu.GeckoMenu;
 import org.mozilla.gecko.menu.GeckoMenuInflater;
 import org.mozilla.gecko.menu.MenuPanel;
 import org.mozilla.gecko.health.BrowserHealthRecorder;
 import org.mozilla.gecko.health.BrowserHealthRecorder.SessionInformation;
 import org.mozilla.gecko.updater.UpdateService;
 import org.mozilla.gecko.updater.UpdateServiceHelper;
+import org.mozilla.gecko.util.ActivityResultHandler;
 import org.mozilla.gecko.util.EventDispatcher;
 import org.mozilla.gecko.util.GeckoEventListener;
 import org.mozilla.gecko.util.GeckoEventResponder;
 import org.mozilla.gecko.util.HardwareUtils;
 import org.mozilla.gecko.util.ThreadUtils;
 import org.mozilla.gecko.util.UiAsyncTask;
 import org.mozilla.gecko.widget.ButtonToast;
 
@@ -58,16 +59,17 @@ import android.net.Uri;
 import android.net.wifi.WifiManager;
 import android.os.Build;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.PowerManager;
 import android.os.StrictMode;
 import android.preference.PreferenceManager;
 import android.provider.ContactsContract;
+import android.provider.MediaStore.Images.Media;
 
 import android.telephony.CellLocation;
 import android.telephony.NeighboringCellInfo;
 import android.telephony.SignalStrength;
 import android.telephony.TelephonyManager;
 import android.telephony.PhoneStateListener;
 import android.telephony.SignalStrength;
 import android.telephony.gsm.GsmCellLocation;
@@ -686,17 +688,17 @@ abstract public class GeckoApp
                 String text = message.getString("text");
                 GeckoAppShell.openUriExternal(text, "text/plain", "", "", Intent.ACTION_SEND, "");
             } else if (event.equals("Share:Image")) {
                 String src = message.getString("url");
                 String type = message.getString("mime");
                 GeckoAppShell.shareImage(src, type);
             } else if (event.equals("Wallpaper:Set")) {
                 String src = message.getString("url");
-                setImageAsWallpaper(src);
+                setImageAs(src);
             } else if (event.equals("Sanitize:ClearHistory")) {
                 handleClearHistory();
             } else if (event.equals("Update:Check")) {
                 startService(new Intent(UpdateServiceHelper.ACTION_CHECK_FOR_UPDATE, null, this, UpdateService.class));
             } else if (event.equals("Update:Download")) {
                 startService(new Intent(UpdateServiceHelper.ACTION_DOWNLOAD_UPDATE, null, this, UpdateService.class));
             } else if (event.equals("Update:Install")) {
                 startService(new Intent(UpdateServiceHelper.ACTION_APPLY_UPDATE, null, this, UpdateService.class));
@@ -966,157 +968,81 @@ abstract public class GeckoApp
                 PluginLayer layer = (PluginLayer) tab.removePluginLayer(view);
                 if (layer != null) {
                     layer.destroy();
                 }
             }
         });
     }
 
-    private void setImageAsWallpaper(final String aSrc) {
-        final String progText = getString(R.string.wallpaper_progress);
-        final String successText = getString(R.string.wallpaper_success);
-        final String failureText = getString(R.string.wallpaper_fail);
-        final String fileName = aSrc.substring(aSrc.lastIndexOf("/") + 1);
-        final PendingIntent emptyIntent = PendingIntent.getActivity(this, 0, new Intent(), 0);
-        final AlertNotification notification = new AlertNotification(this, fileName.hashCode(),
-                                R.drawable.alert_download, fileName, progText, System.currentTimeMillis(), null);
-        notification.setLatestEventInfo(this, fileName, progText, emptyIntent );
-        notification.flags |= Notification.FLAG_ONGOING_EVENT;
-        notification.show();
-        new UiAsyncTask<Void, Void, Boolean>(ThreadUtils.getBackgroundHandler()) {
-
-            @Override
-            protected Boolean doInBackground(Void... params) {
-                WallpaperManager mgr = WallpaperManager.getInstance(GeckoApp.this);
-                if (mgr == null) {
-                    return false;
-                }
-
-                // Determine the ideal width and height of the wallpaper
-                // for the device
-
-                int idealWidth = mgr.getDesiredMinimumWidth();
-                int idealHeight = mgr.getDesiredMinimumHeight();
+    // This method starts downloading an image synchronously and displays the Chooser activity to set the image as wallpaper.
+    private void setImageAs(final String aSrc) {
+        boolean isDataURI = aSrc.startsWith("data:");
+        Bitmap image = null;
+        InputStream is = null;
+        ByteArrayOutputStream os = null;
+        try {
+            if (isDataURI) {
+                int dataStart = aSrc.indexOf(",");
+                byte[] buf = Base64.decode(aSrc.substring(dataStart+1), Base64.DEFAULT);
+                image = BitmapUtils.decodeByteArray(buf);
+            } else {
+                int byteRead;
+                byte[] buf = new byte[4192];
+                os = new ByteArrayOutputStream();
+                URL url = new URL(aSrc);
+                is = url.openStream();
 
-                // Sometimes WallpaperManager's getDesiredMinimum*() methods
-                // can return 0 if a Remote Exception occurs when calling the
-                // Wallpaper Service. So if that fails, we are calculating
-                // the ideal width and height from the device's display 
-                // resolution (excluding the decorated area)
+                // Cannot read from same stream twice. Also, InputStream from
+                // URL does not support reset. So converting to byte array.
 
-                if (idealWidth <= 0 || idealHeight <= 0) {
-                    int orientation;
-                    Display defaultDisplay = getWindowManager().getDefaultDisplay();
-                    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.FROYO) {
-                        orientation = defaultDisplay.getRotation();
-                    } else {
-                        orientation = defaultDisplay.getOrientation();
-                    }
-                    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
-                        Point size = new Point();
-                        defaultDisplay.getSize(size);
-                        // The ideal wallpaper width is always twice the size of
-                        // display width
-                        if (orientation == Surface.ROTATION_0 || orientation == Surface.ROTATION_270) {
-                            idealWidth = size.x * 2;
-                            idealHeight = size.y;
-                        } else {
-                            idealWidth = size.y;
-                            idealHeight = size.x * 2;
-                        }
-                    } else {
-                        if (orientation == Surface.ROTATION_0 || orientation == Surface.ROTATION_270) {
-                            idealWidth = defaultDisplay.getWidth() * 2;
-                            idealHeight = defaultDisplay.getHeight();
-                        } else {
-                            idealWidth = defaultDisplay.getHeight();
-                            idealHeight = defaultDisplay.getWidth() * 2;
-                        }
-                    }
+                while((byteRead = is.read(buf)) != -1) {
+                    os.write(buf, 0, byteRead);
                 }
-
-                boolean isDataURI = aSrc.startsWith("data:");
-                BitmapFactory.Options options = new BitmapFactory.Options();
-                options.inJustDecodeBounds = true;
-                Bitmap image = null;
-                InputStream is = null;
-                ByteArrayOutputStream os = null;
-                try{
-                    if (isDataURI) {
-                        int dataStart = aSrc.indexOf(',');
-                        byte[] buf = Base64.decode(aSrc.substring(dataStart+1), Base64.DEFAULT);
-                        BitmapUtils.decodeByteArray(buf, options);
-                        options.inSampleSize = getBitmapSampleSize(options, idealWidth, idealHeight);
-                        options.inJustDecodeBounds = false;
-                        image = BitmapUtils.decodeByteArray(buf, options);
-                    } else {
-                        int byteRead;
-                        byte[] buf = new byte[4192];
-                        os = new ByteArrayOutputStream();
-                        URL url = new URL(aSrc);
-                        is = url.openStream();
-
-                        // Cannot read from same stream twice. Also, InputStream from
-                        // URL does not support reset. So converting to byte array
+                byte[] imgBuffer = os.toByteArray();
+                image = BitmapUtils.decodeByteArray(imgBuffer);
+            }
+            if (image != null) {
+                String path = Media.insertImage(getContentResolver(),image, null, null);
+                final Intent intent = new Intent(Intent.ACTION_ATTACH_DATA);
+                intent.addCategory(Intent.CATEGORY_DEFAULT);
+                intent.setData(Uri.parse(path));
 
-                        while((byteRead = is.read(buf)) != -1) {
-                            os.write(buf, 0, byteRead);
-                        }
-                        byte[] imgBuffer = os.toByteArray();
-                        BitmapUtils.decodeByteArray(imgBuffer, options);
-                        options.inSampleSize = getBitmapSampleSize(options, idealWidth, idealHeight);
-                        options.inJustDecodeBounds = false;
-                        image = BitmapUtils.decodeByteArray(imgBuffer, options);
-                    }
-                    if(image != null) {
-                        mgr.setBitmap(image);
-                        return true;
-                    } else {
-                        return false;
-                    }
-                } catch(OutOfMemoryError ome) {
-                    Log.e(LOGTAG, "Out of Memory when converting to byte array", ome);
-                    return false;
+                // Removes the image from storage once the chooser activity ends.
+                GeckoAppShell.sActivityHelper.startIntentForActivity(this,
+                                                                    Intent.createChooser(intent, sAppContext.getString(R.string.set_image_chooser_title)),
+                                                                    new ActivityResultHandler() {
+                                                                        @Override
+                                                                        public void onActivityResult (int resultCode, Intent data) {
+                                                                            getContentResolver().delete(intent.getData(), null, null);
+                                                                        }
+                                                                    });
+            } else {
+                Toast.makeText(sAppContext, R.string.set_image_fail, Toast.LENGTH_SHORT).show();
+            }
+        } catch(OutOfMemoryError ome) {
+            Log.e(LOGTAG, "Out of Memory when converting to byte array", ome);
+        } catch(IOException ioe) {
+            Log.e(LOGTAG, "I/O Exception while setting wallpaper", ioe);
+        } finally {
+            if (is != null) {
+                try {
+                    is.close();
                 } catch(IOException ioe) {
-                    Log.e(LOGTAG, "I/O Exception while setting wallpaper", ioe);
-                    return false;
-                } finally {
-                    if(is != null) {
-                        try {
-                            is.close();
-                        } catch(IOException ioe) {
-                            Log.w(LOGTAG, "I/O Exception while closing stream", ioe);
-                        }
-                    }
-                    if(os != null) {
-                        try {
-                            os.close();
-                        } catch(IOException ioe) {
-                            Log.w(LOGTAG, "I/O Exception while closing stream", ioe);
-                        }
-                    }
+                    Log.w(LOGTAG, "I/O Exception while closing stream", ioe);
                 }
             }
-
-            @Override
-            protected void onPostExecute(Boolean success) {
-                notification.cancel();
-                notification.flags = 0;
-                notification.flags |= Notification.FLAG_AUTO_CANCEL;
-                if(!success) {
-                    notification.tickerText = failureText;
-                    notification.setLatestEventInfo(GeckoApp.this, fileName, failureText, emptyIntent);
-                } else {
-                    notification.tickerText = successText;
-                    notification.setLatestEventInfo(GeckoApp.this, fileName, successText, emptyIntent);
+            if (os != null) {
+                try {
+                    os.close();
+                } catch(IOException ioe) {
+                    Log.w(LOGTAG, "I/O Exception while closing stream", ioe);
                 }
-                notification.show();
             }
-        }.execute();
+        }
     }
 
     private int getBitmapSampleSize(BitmapFactory.Options options, int idealWidth, int idealHeight) {
         int width = options.outWidth;
         int height = options.outHeight;
         int inSampleSize = 1;
         if (height > idealHeight || width > idealWidth) {
             if (width > height) {
--- a/mobile/android/base/locales/en-US/android_strings.dtd
+++ b/mobile/android/base/locales/en-US/android_strings.dtd
@@ -190,19 +190,18 @@ size. -->
 <!ENTITY desktop_mode "Request Desktop Site">
 <!ENTITY tools "Tools">
 <!ENTITY new_tab "New Tab">
 <!ENTITY new_private_tab "New Private Tab">
 <!ENTITY close_all_tabs "Close All Tabs">
 <!ENTITY tabs_normal "Tabs">
 <!ENTITY tabs_private "Private">
 <!ENTITY tabs_synced "Synced">
-<!ENTITY wallpaper_success "Wallpaper updated">
-<!ENTITY wallpaper_progress "Setting wallpaper">
-<!ENTITY wallpaper_fail "Unable to set wallpaper">
+<!ENTITY set_image_fail "Unable to set image">
+<!ENTITY set_image_chooser_title "Set Image As">
 
 <!-- Localization note (find_text, find_prev, find_next, find_close) : These strings are used
      as alternate text for accessibility. They are not visible in the UI. -->
 <!ENTITY find_text "Find in Page">
 <!ENTITY find_prev "Previous">
 <!ENTITY find_next "Next">
 <!ENTITY find_close "Close">
 
@@ -343,17 +342,17 @@ just addresses the organization to follo
 <!ENTITY updater_downloading_title_failed2 "Download failed">
 <!ENTITY updater_downloading_select2 "Touch to apply update once downloaded">
 <!ENTITY updater_downloading_retry2 "Touch to retry">
 
 <!ENTITY updater_apply_title2 "Update available for &brandShortName;">
 <!ENTITY updater_apply_select2 "Touch to update">
 
 <!-- Guest mode -->
-<!ENTITY enter_guest_mode "Enter guest mode">
-<!ENTITY exit_guest_mode "Leave guest mode">
-<!ENTITY guest_mode_dialog_continue "Continue">
-<!ENTITY guest_mode_dialog_cancel "Cancel">
-<!ENTITY guest_mode_enter_title "Guest mode">
-<!ENTITY guest_mode_enter_text "While in guest mode, the person using &brandShortName; will not be able to see any of your personal browsing data (like your saved passwords, history or bookmarks).\n\nWhen your guest is done, their browsing data will be deleted.">
+<!ENTITY new_guest_session "New Guest Session">
+<!ENTITY exit_guest_session "Exit Guest Session">
+<!ENTITY guest_session_dialog_continue "Continue">
+<!ENTITY guest_session_dialog_cancel "Cancel">
+<!ENTITY new_guest_session_title "&brandShortName; will now restart">
+<!ENTITY new_guest_session_text "The person using it will not be able to see any of your personal browsing data (like saved passwords, history or bookmarks).\n\nWhen your guest is done, their browsing data will be deleted and your session will be restored.">
 
-<!ENTITY guest_mode_leave_title "Leaving guest mode">
-<!ENTITY guest_mode_leave_text "&brandShortName; will delete browsing data from this session.">
+<!ENTITY exit_guest_session_title "&brandShortName; will now restart">
+<!ENTITY exit_guest_session_text "The browsing data from this session will be deleted.">
--- a/mobile/android/base/resources/menu-large-v11/browser_app_menu.xml
+++ b/mobile/android/base/resources/menu-large-v11/browser_app_menu.xml
@@ -70,16 +70,16 @@
           android:icon="@drawable/ic_menu_character_encoding"
           android:visible="false"
           android:title="@string/char_encoding"/>
 
     <item android:id="@+id/settings"
           android:icon="@drawable/ic_menu_settings"
           android:title="@string/settings" />
 
-    <item android:id="@+id/enter_guest_mode"
+    <item android:id="@+id/new_guest_session"
           android:visible="false"
-          android:title="@string/enter_guest_mode"/>
+          android:title="@string/new_guest_session"/>
 
-    <item android:id="@+id/exit_guest_mode"
+    <item android:id="@+id/exit_guest_session"
           android:visible="false"
-          android:title="@string/exit_guest_mode"/>
+          android:title="@string/exit_guest_session"/>
 </menu>
--- a/mobile/android/base/resources/menu-v11/browser_app_menu.xml
+++ b/mobile/android/base/resources/menu-v11/browser_app_menu.xml
@@ -71,16 +71,16 @@
           android:icon="@drawable/ic_menu_character_encoding"
           android:visible="false"
           android:title="@string/char_encoding"/>
 
     <item android:id="@+id/settings"
           android:icon="@drawable/ic_menu_settings"
           android:title="@string/settings" />
 
-    <item android:id="@+id/enter_guest_mode"
+    <item android:id="@+id/new_guest_session"
           android:visible="false"
-          android:title="@string/enter_guest_mode"/>
+          android:title="@string/new_guest_session"/>
 
-    <item android:id="@+id/exit_guest_mode"
+    <item android:id="@+id/exit_guest_session"
           android:visible="false"
-          android:title="@string/exit_guest_mode"/>
+          android:title="@string/exit_guest_session"/>
 </menu>
--- a/mobile/android/base/resources/menu-xlarge-v11/browser_app_menu.xml
+++ b/mobile/android/base/resources/menu-xlarge-v11/browser_app_menu.xml
@@ -71,16 +71,16 @@
           android:icon="@drawable/ic_menu_character_encoding"
           android:visible="false"
           android:title="@string/char_encoding"/>
 
     <item android:id="@+id/settings"
           android:icon="@drawable/ic_menu_settings"
           android:title="@string/settings" />
 
-    <item android:id="@+id/enter_guest_mode"
+    <item android:id="@+id/new_guest_session"
           android:visible="false"
-          android:title="@string/enter_guest_mode"/>
+          android:title="@string/new_guest_session"/>
 
-    <item android:id="@+id/exit_guest_mode"
+    <item android:id="@+id/exit_guest_session"
           android:visible="false"
-          android:title="@string/exit_guest_mode"/>
+          android:title="@string/exit_guest_session"/>
 </menu>
--- a/mobile/android/base/resources/menu/browser_app_menu.xml
+++ b/mobile/android/base/resources/menu/browser_app_menu.xml
@@ -49,16 +49,16 @@
 
     <item android:id="@+id/char_encoding"
           android:visible="false"
           android:title="@string/char_encoding"/>
 
     <item android:id="@+id/settings"
           android:title="@string/settings" />
 
-    <item android:id="@+id/enter_guest_mode"
+    <item android:id="@+id/new_guest_session"
           android:visible="false"
-          android:title="@string/enter_guest_mode"/>
+          android:title="@string/new_guest_session"/>
 
-    <item android:id="@+id/exit_guest_mode"
+    <item android:id="@+id/exit_guest_session"
           android:visible="false"
-          android:title="@string/exit_guest_mode"/>
+          android:title="@string/exit_guest_session"/>
 </menu>
--- a/mobile/android/base/strings.xml.in
+++ b/mobile/android/base/strings.xml.in
@@ -316,28 +316,27 @@
   <string name="updater_downloading_retry">&updater_downloading_retry2;</string>
 
   <string name="updater_apply_title">&updater_apply_title2;</string>
   <string name="updater_apply_select">&updater_apply_select2;</string>
 
   <!-- Search suggestions opt-in -->
   <string name="suggestions_prompt">&suggestions_prompt2;</string>
 
-  <!-- Wallpaper Notifications -->
-  <string name="wallpaper_success">&wallpaper_success;</string>
-  <string name="wallpaper_progress">&wallpaper_progress;</string>
-  <string name="wallpaper_fail">&wallpaper_fail;</string>
+  <!-- Set Image Notifications -->
+  <string name="set_image_fail">&set_image_fail;</string>
+  <string name="set_image_chooser_title">&set_image_chooser_title;</string>
 
   <!-- Contacts API -->
   <string name="contacts_account_chooser_dialog_title">Share contacts from...</string>
 
 
   <!-- Guest mode -->
-  <string name="enter_guest_mode">&enter_guest_mode;</string>
-  <string name="exit_guest_mode">&exit_guest_mode;</string>
-  <string name="guest_mode_dialog_continue">&guest_mode_dialog_continue;</string>
-  <string name="guest_mode_dialog_cancel">&guest_mode_dialog_cancel;</string>
-  <string name="guest_mode_enter_title">&guest_mode_enter_title;</string>
-  <string name="guest_mode_enter_text">&guest_mode_enter_text;</string>
+  <string name="new_guest_session">&new_guest_session;</string>
+  <string name="exit_guest_session">&exit_guest_session;</string>
+  <string name="guest_session_dialog_continue">&guest_session_dialog_continue;</string>
+  <string name="guest_session_dialog_cancel">&guest_session_dialog_cancel;</string>
+  <string name="new_guest_session_title">&new_guest_session_title;</string>
+  <string name="new_guest_session_text">&new_guest_session_text;</string>
 
-  <string name="guest_mode_leave_title">&guest_mode_leave_title;</string>
-  <string name="guest_mode_leave_text">&guest_mode_leave_text;</string>
+  <string name="exit_guest_session_title">&exit_guest_session_title;</string>
+  <string name="exit_guest_session_text">&exit_guest_session_text;</string>
 </resources>
--- a/mobile/android/base/tests/testWebContentContextMenu.java.in
+++ b/mobile/android/base/tests/testWebContentContextMenu.java.in
@@ -18,17 +18,17 @@ public class testWebContentContextMenu e
     }
 
     public void testWebContentContextMenu() {
         blockForGeckoReady();
 
         String urls [] = { "/robocop/robocop_big_link.html", "/robocop/robocop_big_mailto.html", "/robocop/robocop_picture_link.html"};
         String linkMenuItems [] = { "Open Link in New Tab", "Open Link in Private Tab", "Copy Link", "Share Link", "Bookmark Link"};
         String mailtoMenuItems [] = { "Open With an App", "Copy Email Address", "Share Email Address"};
-        String photoMenuItems [] = { "Copy Image Location", "Share Image", "Set as Wallpaper", "Save Image"};
+        String photoMenuItems [] = { "Copy Image Location", "Share Image", "Set Image As", "Save Image"};
 
         verfyLinkContextMenu(linkMenuItems, urls);
         verfyMailtoContextMenu(mailtoMenuItems, urls);
         verfyPhotoContextMenu(photoMenuItems, urls);
 
     }
 
     public void openContextMenu(int i, String urls []) {
@@ -187,17 +187,17 @@ public class testWebContentContextMenu e
                     accessSection(2, opt, urls);
 
                     // Verifying if the Share Image option menu is opened
                     mAsserter.ok(mSolo.waitForText("Share via"), "Waiting for the Share Image option menu to open", "The Share Image option menu is opened");
                     mActions.sendSpecialKey(Actions.SpecialKey.BACK); // Close the Share Image option menu
                     mSolo.waitForText("Picture Link");
                 }
                 else {
-                    if (opt.equals("Set as Wallpaper")) {
+                    if (opt.equals("Set Image As")) {
                         openContextMenu(2, urls);
                         mAsserter.ok(mSolo.waitForText(opt), "Waiting for  " + opt + "  option", "The " + opt + "  option is present");
                     }
                     else {
                         if (opt.equals("Save Image")) {
                             mSolo.clickOnText(opt);
                             mAsserter.ok(mSolo.waitForText("Download started"), "Verify that the download started", "The download started");
                             mSolo.waitForText("Picture Link");
--- a/mobile/android/chrome/content/browser.js
+++ b/mobile/android/chrome/content/browser.js
@@ -590,27 +590,25 @@ var BrowserApp = {
     NativeWindow.contextmenus.add(Strings.browser.GetStringFromName("contextmenu.saveImage"),
       NativeWindow.contextmenus.imageSaveableContext,
       function(aTarget) {
         ContentAreaUtils.saveImageURL(aTarget.currentURI.spec, null, "SaveImageTitle",
                                       false, true, aTarget.ownerDocument.documentURIObject,
                                       aTarget.ownerDocument);
       });
 
-#ifdef MOZ_ANDROID_WALLPAPER
-    NativeWindow.contextmenus.add(Strings.browser.GetStringFromName("contextmenu.setWallpaper"),
+    NativeWindow.contextmenus.add(Strings.browser.GetStringFromName("contextmenu.setImageAs"),
       NativeWindow.contextmenus.imageSaveableContext,
       function(aTarget) {
         let src = aTarget.src;
         sendMessageToJava({
           type: "Wallpaper:Set",
           url: src
         });
       });
-#endif
 
     NativeWindow.contextmenus.add(
       function(aTarget) {
         if (aTarget instanceof HTMLVideoElement) {
           // If a video element is zero width or height, its essentially
           // an HTMLAudioElement.
           if (aTarget.videoWidth == 0 || aTarget.videoHeight == 0 )
             return Strings.browser.GetStringFromName("contextmenu.saveAudio");
--- a/mobile/android/confvars.sh
+++ b/mobile/android/confvars.sh
@@ -14,19 +14,16 @@ MOZ_OFFICIAL_BRANDING_DIRECTORY=mobile/a
 
 MOZ_SAFE_BROWSING=1
 
 MOZ_DISABLE_CRYPTOLEGACY=1
 
 # Enable getUserMedia
 MOZ_MEDIA_NAVIGATOR=1
 
-# Enable SET_WALLPAPER permission
-MOZ_ANDROID_WALLPAPER=1
-
 # Enable NFC permission
 MOZ_ANDROID_BEAM=1
 
 if test "$LIBXUL_SDK"; then
 MOZ_XULRUNNER=1
 else
 MOZ_XULRUNNER=
 fi
--- a/mobile/android/locales/en-US/chrome/browser.properties
+++ b/mobile/android/locales/en-US/chrome/browser.properties
@@ -165,17 +165,17 @@ contextmenu.changeInputMethod=Select Inp
 contextmenu.fullScreen=Full Screen
 contextmenu.copyImageLocation=Copy Image Location
 contextmenu.shareImage=Share Image
 # LOCALIZATION NOTE (contextmenu.search):
 # The label of the contextmenu item which allows you to search with your default search engine for
 # the text you have selected. %S is the name of the search engine. For example, "Google".
 contextmenu.search=%S Search
 contextmenu.saveImage=Save Image
-contextmenu.setWallpaper=Set as Wallpaper
+contextmenu.setImageAs=Set Image As
 contextmenu.addSearchEngine=Add Search Engine
 contextmenu.playMedia=Play
 contextmenu.pauseMedia=Pause
 contextmenu.shareMedia=Share Video
 contextmenu.showControls2=Show Controls
 contextmenu.mute=Mute
 contextmenu.unmute=Unmute
 contextmenu.saveVideo=Save Video
--- a/testing/mochitest/mochitest_options.py
+++ b/testing/mochitest/mochitest_options.py
@@ -463,17 +463,17 @@ class MochitestOptions(optparse.OptionPa
         if options.runUntilFailure:
             if not os.path.isfile(os.path.join(mochitest.oldcwd, os.path.dirname(__file__), mochitest.getTestRoot(options), options.testPath)):
                 self.error("--run-until-failure can only be used together with --test-path specifying a single test.")
             if not options.repeat:
                 options.repeat = 29
 
         if not options.mozInfo:
             if build_obj:
-                options.mozInfo = os.path.join(build_obj.get_binary_path(), 'mozinfo.json')
+                options.mozInfo = os.path.join(build_obj.topobjdir, 'mozinfo.json')
             else:
                 options.mozInfo = os.path.abspath('mozinfo.json')
 
         if not os.path.isfile(options.mozInfo):
             self.error("Unable to file build information file (mozinfo.json) at this location: %s" % options.mozInfo)
 
         return options
 
--- a/toolkit/components/jsdownloads/src/DownloadCore.jsm
+++ b/toolkit/components/jsdownloads/src/DownloadCore.jsm
@@ -306,20 +306,21 @@ Download.prototype = {
     // it comes in late from a download attempt that was replaced by a new one.
     function DS_setProgressBytes(aCurrentBytes, aTotalBytes, aHasPartialData)
     {
       if (this._currentAttempt == currentAttempt || !this._currentAttempt) {
         this._setBytes(aCurrentBytes, aTotalBytes, aHasPartialData);
       }
     }
 
-    // This function propragates download properties from the DownloadSaver
+    // This function propagates download properties from the DownloadSaver
     // object, unless it comes in late from a download attempt that was
     // replaced by a new one.
-    function DS_setDownloadProperties(aOptions) {
+    function DS_setProperties(aOptions)
+    {
       if (this._currentAttempt && this._currentAttempt != currentAttempt) {
         return;
       }
 
       let changeMade = false;
 
       if ("contentType" in aOptions &&
           this.contentType != aOptions.contentType) {
@@ -354,17 +355,17 @@ Download.prototype = {
         error.becauseBlocked = true;
         error.becauseBlockedByParentalControls = true;
         throw error;
       }
 
       try {
         // Execute the actual download through the saver object.
         yield this.saver.execute(DS_setProgressBytes.bind(this),
-                                 DS_setDownloadProperties.bind(this));
+                                 DS_setProperties.bind(this));
 
         // Update the status properties for a successful download.
         this.progress = 100;
         this.succeeded = true;
       } catch (ex) {
         // Fail with a generic status code on cancellation, so that the caller
         // is forced to actually check the status properties to see if the
         // download was canceled or failed because of other reasons.
@@ -1013,17 +1014,17 @@ DownloadSaver.prototype = {
    *
    * @param aSetProgressBytesFn
    *        This function may be called by the saver to report progress. It
    *        takes three arguments: the first is the number of bytes transferred
    *        until now, the second is the total number of bytes to be
    *        transferred (or -1 if unknown), the third indicates whether the
    *        partially downloaded data can be used when restarting the download
    *        if it fails or is canceled.
-   * @parem aSetPropertiesFn
+   * @param aSetPropertiesFn
    *        This function may be called by the saver to report information
    *        about new download properties discovered by the saver during the
    *        download process. It takes an object where the keys represents
    *        the names of the properties to set, and the value represents the
    *        value to set.
    *
    * @return {Promise}
    * @resolves When the download has finished successfully.
@@ -1228,23 +1229,23 @@ DownloadCopySaver.prototype = {
           };
 
           // Open the channel, directing output to the background file saver.
           backgroundFileSaver.QueryInterface(Ci.nsIStreamListener);
           channel.asyncOpen({
             onStartRequest: function (aRequest, aContext) {
               backgroundFileSaver.onStartRequest(aRequest, aContext);
 
+              aSetPropertiesFn({ contentType: channel.contentType });
+
               // Ensure we report the value of "Content-Length", if available,
               // even if the download doesn't generate any progress events
               // later.
-              if (aRequest instanceof Ci.nsIChannel &&
-                  aRequest.contentLength >= 0) {
-                aSetProgressBytesFn(0, aRequest.contentLength);
-                aSetPropertiesFn({ contentType: aRequest.contentType });
+              if (channel.contentLength >= 0) {
+                aSetProgressBytesFn(0, channel.contentLength);
               }
 
               if (keepPartialData) {
                 // If the source is not resumable, don't keep partial data even
                 // if we were asked to try and do it.
                 if (aRequest instanceof Ci.nsIResumableChannel) {
                   try {
                     // If reading the ID succeeds, the source is resumable.
--- a/toolkit/components/jsdownloads/src/DownloadIntegration.jsm
+++ b/toolkit/components/jsdownloads/src/DownloadIntegration.jsm
@@ -338,34 +338,36 @@ this.DownloadIntegration = {
           // This should not happen on normal circumstances because launcherPath
           // is only set when we had an instance of nsIMIMEInfo to retrieve
           // the custom application chosen by the user.
           throw new Error(
             "Unable to create nsIMIMEInfo to launch a custom application");
         }
 
         // Custom application chosen
-        mimeInfo.preferredAction = Ci.nsIMIMEInfo.useHelperApp;
-
         let localHandlerApp = Cc["@mozilla.org/uriloader/local-handler-app;1"]
                                 .createInstance(Ci.nsILocalHandlerApp);
         localHandlerApp.executable = new FileUtils.File(aDownload.launcherPath);
 
+        mimeInfo.preferredApplicationHandler = localHandlerApp;
+        mimeInfo.preferredAction = Ci.nsIMIMEInfo.useHelperApp;
+
+        // In test mode, allow the test to verify the nsIMIMEInfo instance.
         if (this.dontOpenFileAndFolder) {
-          throw new Task.Result("chosen-app");
+          throw new Task.Result(mimeInfo);
         }
 
         mimeInfo.launchWithFile(file);
         return;
       }
 
-      // No custom application chosen, let's launch the file with the
-      // default handler
+      // No custom application chosen, let's launch the file with the default
+      // handler.  In test mode, we indicate this with a null value.
       if (this.dontOpenFileAndFolder) {
-        throw new Task.Result("default-handler");
+        throw new Task.Result(null);
       }
 
       // First let's try to launch it through the MIME service application
       // handler
       if (mimeInfo) {
         mimeInfo.preferredAction = Ci.nsIMIMEInfo.useSystemDefault;
 
         try {
--- a/toolkit/components/jsdownloads/src/DownloadLegacy.js
+++ b/toolkit/components/jsdownloads/src/DownloadLegacy.js
@@ -159,38 +159,38 @@ DownloadLegacyTransfer.prototype = {
   },
 
   //////////////////////////////////////////////////////////////////////////////
   //// nsITransfer
 
   init: function DLT_init(aSource, aTarget, aDisplayName, aMIMEInfo, aStartTime,
                           aTempFile, aCancelable, aIsPrivate)
   {
-
-    let launchWhenSuccedded = false, contentType = null, launcherPath = null;
+    let launchWhenSucceeded = false, contentType = null, launcherPath = null;
 
     if (aMIMEInfo instanceof Ci.nsIMIMEInfo) {
-      launchWhenSuccedded = aMIMEInfo.preferredAction != Ci.nsIMIMEInfo.saveToDisk;
+      launchWhenSucceeded =
+                aMIMEInfo.preferredAction != Ci.nsIMIMEInfo.saveToDisk;
       contentType = aMIMEInfo.type;
+
       let appHandler = aMIMEInfo.preferredApplicationHandler;
-
       if (appHandler instanceof Ci.nsILocalHandlerApp) {
-        launcherPath = localHandler.executable.path;
+        launcherPath = appHandler.executable.path;
       }
     }
 
     // Create a new Download object associated to a DownloadLegacySaver, and
     // wait for it to be available.  This operation may cause the entire
     // download system to initialize before the object is created.
     Downloads.createDownload({
       source: { url: aSource.spec, isPrivate: aIsPrivate },
       target: { path: aTarget.QueryInterface(Ci.nsIFileURL).file.path,
                 partFilePath: aTempFile && aTempFile.path },
       saver: "legacy",
-      launchWhenSuccedded: launchWhenSuccedded,
+      launchWhenSucceeded: launchWhenSucceeded,
       contentType: contentType,
       launcherPath: launcherPath
     }).then(function DLT_I_onDownload(aDownload) {
       // Now that the saver is available, hook up the cancellation handler.
       aDownload.saver.deferCanceled.promise.then(() => {
         // Only cancel if the object executing the download is still running.
         if (!this._componentFailed) {
           aCancelable.cancel(Cr.NS_ERROR_ABORT);
--- a/toolkit/components/jsdownloads/test/unit/common_test_Download.js
+++ b/toolkit/components/jsdownloads/test/unit/common_test_Download.js
@@ -349,16 +349,19 @@ add_task(function test_empty_progress()
   yield promiseDownloadStopped(download);
 
   do_check_true(download.stopped);
   do_check_true(download.hasProgress);
   do_check_eq(download.progress, 100);
   do_check_eq(download.currentBytes, 0);
   do_check_eq(download.totalBytes, 0);
 
+  // We should have received the content type even for an empty file.
+  do_check_eq(download.contentType, "text/plain");
+
   do_check_eq((yield OS.File.stat(download.target.path)).size, 0);
 });
 
 /**
  * Downloads an empty file with no "Content-Length" and checks the progress.
  */
 add_task(function test_empty_noprogress()
 {
@@ -414,16 +417,19 @@ add_task(function test_empty_noprogress(
   do_check_false(download.hasProgress);
   do_check_eq(download.currentBytes, 0);
   do_check_eq(download.totalBytes, 0);
 
   // Now allow the response to finish.
   continueResponses();
   yield promiseDownloadStopped(download);
 
+  // We should have received the content type even if no progress is reported.
+  do_check_eq(download.contentType, "text/plain");
+
   // Verify the state of the completed download.
   do_check_true(download.stopped);
   do_check_false(download.hasProgress);
   do_check_eq(download.progress, 100);
   do_check_eq(download.currentBytes, 0);
   do_check_eq(download.totalBytes, 0);
 
   do_check_eq((yield OS.File.stat(download.target.path)).size, 0);
@@ -1396,116 +1402,137 @@ add_task(function test_showContainingDir
   let result = yield DownloadIntegration._deferTestShowDir.promise;
   do_check_eq(result, "success");
 });
 
 /**
  * download.launch() action
  */
 add_task(function test_launch() {
-  let targetPath = getTempFile(TEST_TARGET_FILE_NAME).path;
+  let customLauncher = getTempFile("app-launcher");
+
+  // Test both with and without setting a custom application.
+  for (let launcherPath of [null, customLauncher.path]) {
+    let download;
+    if (!gUseLegacySaver) {
+      // When testing DownloadCopySaver, we have control over the download, thus
+      // we can test that file is not launched if download.succeeded is not set.
+      download = yield Downloads.createDownload({
+        source: httpUrl("source.txt"),