Merge mozilla-central to mozilla-inbound.
authorSiddharth Agarwal <sid.bugzilla@gmail.com>
Thu, 23 Aug 2012 23:59:41 +0530
changeset 105231 3de71b93776b59122bde4f6464e6a0bc3a6dc732
parent 105230 2c90590561194f511e388e53ec0f251634aef6a8 (current diff)
parent 105158 ad7963c93bd8e334e06433b6357fe0a432f107df (diff)
child 105232 16e1ff49a6a5e908f3923991c7b9e39f62cd8919
push id55
push usershu@rfrn.org
push dateThu, 30 Aug 2012 01:33:09 +0000
milestone17.0a1
Merge mozilla-central to mozilla-inbound.
--- a/browser/app/profile/firefox.js
+++ b/browser/app/profile/firefox.js
@@ -1085,16 +1085,19 @@ pref("devtools.webconsole.filter.csserro
 pref("devtools.webconsole.filter.cssparser", true);
 pref("devtools.webconsole.filter.exception", true);
 pref("devtools.webconsole.filter.jswarn", true);
 pref("devtools.webconsole.filter.error", true);
 pref("devtools.webconsole.filter.warn", true);
 pref("devtools.webconsole.filter.info", true);
 pref("devtools.webconsole.filter.log", true);
 
+// Text size in the Web Console. Use 0 for the system default size.
+pref("devtools.webconsole.fontSize", 0);
+
 // The number of lines that are displayed in the web console for the Net,
 // CSS, JS and Web Developer categories.
 pref("devtools.hud.loglimit.network", 200);
 pref("devtools.hud.loglimit.cssparser", 200);
 pref("devtools.hud.loglimit.exception", 200);
 pref("devtools.hud.loglimit.console", 200);
 
 // The developer tools editor configuration:
--- a/browser/devtools/debugger/debugger-controller.js
+++ b/browser/devtools/debugger/debugger-controller.js
@@ -180,31 +180,24 @@ let DebuggerController = {
     this.client.close();
 
     this.client = null;
     this.tabClient = null;
     this.activeThread = null;
   },
 
   /**
-   * Starts debugging the current tab. This function is called on each location
-   * change in this tab.
+   * This function is called on each location change in this tab.
    */
   _onTabNavigated: function DC__onTabNavigated(aNotification, aPacket) {
-    let client = this.client;
-
-    client.activeThread.detach(function() {
-      client.activeTab.detach(function() {
-        client.listTabs(function(aResponse) {
-          let tab = aResponse.tabs[aResponse.selected];
-          this._startDebuggingTab(client, tab);
-          this.dispatchEvent("Debugger:Connecting");
-        }.bind(this));
-      }.bind(this));
-    }.bind(this));
+    DebuggerController.ThreadState._handleTabNavigation(function() {
+      DebuggerController.StackFrames._handleTabNavigation(function() {
+        DebuggerController.SourceScripts._handleTabNavigation();
+      });
+    });
   },
 
   /**
    * Stops debugging the current tab.
    */
   _onTabDetached: function DC__onTabDetached() {
     this.dispatchEvent("Debugger:Close");
   },
@@ -322,17 +315,17 @@ ThreadState.prototype = {
    * @param function aCallback
    *        The next function in the initialization sequence.
    */
   connect: function TS_connect(aCallback) {
     this.activeThread.addListener("paused", this._update);
     this.activeThread.addListener("resumed", this._update);
     this.activeThread.addListener("detached", this._update);
 
-    this._update();
+    this._handleTabNavigation();
 
     aCallback && aCallback();
   },
 
   /**
    * Disconnect from the client.
    */
   disconnect: function TS_disconnect() {
@@ -340,16 +333,25 @@ ThreadState.prototype = {
       return;
     }
     this.activeThread.removeListener("paused", this._update);
     this.activeThread.removeListener("resumed", this._update);
     this.activeThread.removeListener("detached", this._update);
   },
 
   /**
+   * Handles any initialization on a tab navigation event issued by the client.
+   */
+  _handleTabNavigation: function TS__handleTabNavigation(aCallback) {
+    DebuggerView.StackFrames.updateState(this.activeThread.state);
+
+    aCallback && aCallback();
+  },
+
+  /**
    * Update the UI after a thread state change.
    */
   _update: function TS__update(aEvent) {
     DebuggerView.StackFrames.updateState(this.activeThread.state);
   }
 };
 
 /**
@@ -392,55 +394,64 @@ StackFrames.prototype = {
   /**
    * Watch the given thread client.
    *
    * @param function aCallback
    *        The next function in the initialization sequence.
    */
   connect: function SF_connect(aCallback) {
     window.addEventListener("Debugger:FetchedVariables", this._onFetchedVars, false);
-
     this.activeThread.addListener("paused", this._onPaused);
     this.activeThread.addListener("resumed", this._onResume);
     this.activeThread.addListener("framesadded", this._onFrames);
     this.activeThread.addListener("framescleared", this._onFramesCleared);
 
+    this._handleTabNavigation();
     this.updatePauseOnExceptions(this.pauseOnExceptions);
 
     aCallback && aCallback();
   },
 
   /**
    * Disconnect from the client.
    */
   disconnect: function SF_disconnect() {
-    window.removeEventListener("Debugger:FetchedVariables", this._onFetchedVars, false);
-
     if (!this.activeThread) {
       return;
     }
+    window.removeEventListener("Debugger:FetchedVariables", this._onFetchedVars, false);
     this.activeThread.removeListener("paused", this._onPaused);
     this.activeThread.removeListener("resumed", this._onResume);
     this.activeThread.removeListener("framesadded", this._onFrames);
     this.activeThread.removeListener("framescleared", this._onFramesCleared);
   },
 
   /**
+   * Handles any initialization on a tab navigation event issued by the client.
+   */
+  _handleTabNavigation: function SF__handleTabNavigation(aCallback) {
+    // Nothing to do here yet.
+
+    aCallback && aCallback();
+  },
+
+  /**
    * Handler for the thread client's paused notification.
    *
    * @param string aEvent
    *        The name of the notification ("paused" in this case).
    * @param object aPacket
    *        The response packet.
    */
   _onPaused: function SF__onPaused(aEvent, aPacket) {
     // In case the pause was caused by an exception, store the exception value.
     if (aPacket.why.type == "exception") {
       this.exception = aPacket.why.exception;
     }
+
     this.activeThread.fillFrames(this.pageSize);
     DebuggerView.editor.focus();
   },
 
   /**
    * Handler for the thread client's resumed notification.
    */
   _onResume: function SF__onResume() {
@@ -829,17 +840,16 @@ StackFrames.prototype = {
 
 /**
  * Keeps the source script list up-to-date, using the thread client's
  * source script cache.
  */
 function SourceScripts() {
   this._onNewScript = this._onNewScript.bind(this);
   this._onScriptsAdded = this._onScriptsAdded.bind(this);
-  this._onScriptsCleared = this._onScriptsCleared.bind(this);
   this._onShowScript = this._onShowScript.bind(this);
   this._onLoadSource = this._onLoadSource.bind(this);
   this._onLoadSourceFinished = this._onLoadSourceFinished.bind(this);
 }
 
 SourceScripts.prototype = {
 
   /**
@@ -864,91 +874,107 @@ SourceScripts.prototype = {
   /**
    * Watch the given thread client.
    *
    * @param function aCallback
    *        The next function in the initialization sequence.
    */
   connect: function SS_connect(aCallback) {
     window.addEventListener("Debugger:LoadSource", this._onLoadSource, false);
-
     this.debuggerClient.addListener("newScript", this._onNewScript);
-    this.activeThread.addListener("scriptsadded", this._onScriptsAdded);
-    this.activeThread.addListener("scriptscleared", this._onScriptsCleared);
 
-    this._clearLabelsCache();
-    this._onScriptsCleared();
-
-    // Retrieve the list of scripts known to the server from before the client
-    // was ready to handle new script notifications.
-    this.activeThread.fillScripts();
+    this._handleTabNavigation();
 
     aCallback && aCallback();
   },
 
   /**
    * Disconnect from the client.
    */
-  disconnect: function TS_disconnect() {
-    window.removeEventListener("Debugger:LoadSource", this._onLoadSource, false);
-
+  disconnect: function SS_disconnect() {
     if (!this.activeThread) {
       return;
     }
+    window.removeEventListener("Debugger:LoadSource", this._onLoadSource, false);
     this.debuggerClient.removeListener("newScript", this._onNewScript);
-    this.activeThread.removeListener("scriptsadded", this._onScriptsAdded);
-    this.activeThread.removeListener("scriptscleared", this._onScriptsCleared);
+  },
+
+  /**
+   * Handles any initialization on a tab navigation event issued by the client.
+   */
+  _handleTabNavigation: function SS__handleTabNavigation(aCallback) {
+    this._clearLabelsCache();
+    this._onScriptsCleared();
+
+    // Retrieve the list of scripts known to the server from before the client
+    // was ready to handle new script notifications.
+    this.activeThread.getScripts(this._onScriptsAdded);
+
+    aCallback && aCallback();
   },
 
   /**
    * Handler for the debugger client's unsolicited newScript notification.
    */
   _onNewScript: function SS__onNewScript(aNotification, aPacket) {
     // Ignore scripts generated from 'clientEvaluate' packets.
     if (aPacket.url == "debugger eval code") {
       return;
     }
 
     this._addScript({ url: aPacket.url, startLine: aPacket.startLine }, true);
 
-    // Select the script if it's the preferred one.
+    let preferredScriptUrl = DebuggerView.Scripts.preferredScriptUrl;
+
+    // Select this script if it's the preferred one.
     if (aPacket.url === DebuggerView.Scripts.preferredScriptUrl) {
       DebuggerView.Scripts.selectScript(aPacket.url);
     }
+    // ..or the first entry if there's not one selected yet.
+    else if (!DebuggerView.Scripts.selected) {
+      DebuggerView.Scripts.selectIndex(0);
+    }
 
     // If there are any stored breakpoints for this script, display them again,
     // both in the editor and the pane.
     for each (let breakpoint in DebuggerController.Breakpoints.store) {
       if (breakpoint.location.url == aPacket.url) {
         DebuggerController.Breakpoints.displayBreakpoint(breakpoint);
       }
     }
+
+    DebuggerController.dispatchEvent("Debugger:AfterNewScript");
   },
 
   /**
-   * Handler for the thread client's scriptsadded notification.
+   * Callback for the getScripts() method.
    */
-  _onScriptsAdded: function SS__onScriptsAdded() {
-    for each (let script in this.activeThread.cachedScripts) {
+  _onScriptsAdded: function SS__onScriptsAdded(aResponse) {
+    for each (let script in aResponse.scripts) {
       this._addScript(script, false);
     }
     DebuggerView.Scripts.commitScripts();
     DebuggerController.Breakpoints.updatePaneBreakpoints();
 
-    // Select the preferred script if one exists, the first entry otherwise.
     let preferredScriptUrl = DebuggerView.Scripts.preferredScriptUrl;
+
+    // Select the preferred script if it exists and was part of the response.
     if (preferredScriptUrl && DebuggerView.Scripts.contains(preferredScriptUrl)) {
       DebuggerView.Scripts.selectScript(preferredScriptUrl);
-    } else {
+    }
+    // ..or the first entry if there's not one selected yet.
+    else if (!DebuggerView.Scripts.selected) {
       DebuggerView.Scripts.selectIndex(0);
     }
+
+    DebuggerController.dispatchEvent("Debugger:AfterScriptsAdded");
   },
 
   /**
-   * Handler for the thread client's scriptscleared notification.
+   * Called during navigation to clear the currently-loaded scripts.
    */
   _onScriptsCleared: function SS__onScriptsCleared() {
     DebuggerView.Scripts.empty();
     DebuggerView.Breakpoints.emptyText();
     DebuggerView.editor.setText("");
   },
 
   /**
--- a/browser/devtools/debugger/test/browser_dbg_bfcache.js
+++ b/browser/devtools/debugger/test/browser_dbg_bfcache.js
@@ -35,50 +35,62 @@ function testInitialLoad() {
   });
 
   gDebuggee.firstCall();
 }
 
 function testLocationChange()
 {
   gDebugger.DebuggerController.activeThread.resume(function() {
-    gDebugger.DebuggerController.client.addOneTimeListener("tabAttached", function(aEvent, aPacket) {
-      ok(true, "Successfully reattached to the tab again.");
-      gDebugger.DebuggerController.client.addOneTimeListener("resumed", function(aEvent, aPacket) {
+    gDebugger.DebuggerController.client.addOneTimeListener("tabNavigated", function(aEvent, aPacket) {
+      ok(true, "tabNavigated event was fired.");
+      info("Still attached to the tab.");
+
+      gDebugger.addEventListener("Debugger:AfterScriptsAdded", function _onEvent(aEvent) {
+        gDebugger.removeEventListener(aEvent.type, _onEvent);
+
         executeSoon(function() {
           validateSecondPage();
           testBack();
         });
       });
     });
     content.location = STACK_URL;
   });
 }
 
 function testBack()
 {
-  gDebugger.DebuggerController.client.addOneTimeListener("tabAttached", function(aEvent, aPacket) {
-    ok(true, "Successfully reattached to the tab after going back.");
-    gDebugger.DebuggerController.client.addOneTimeListener("resumed", function(aEvent, aPacket) {
+  gDebugger.DebuggerController.client.addOneTimeListener("tabNavigated", function(aEvent, aPacket) {
+    ok(true, "tabNavigated event was fired after going back.");
+    info("Still attached to the tab.");
+
+    gDebugger.addEventListener("Debugger:AfterScriptsAdded", function _onEvent(aEvent) {
+      gDebugger.removeEventListener(aEvent.type, _onEvent);
+
       executeSoon(function() {
         validateFirstPage();
         testForward();
       });
     });
   });
 
   info("Going back.");
   content.history.back();
 }
 
 function testForward()
 {
-  gDebugger.DebuggerController.client.addOneTimeListener("tabAttached", function(aEvent, aPacket) {
-    ok(true, "Successfully reattached to the tab after going forward.");
-    gDebugger.DebuggerController.client.addOneTimeListener("resumed", function(aEvent, aPacket) {
+  gDebugger.DebuggerController.client.addOneTimeListener("tabNavigated", function(aEvent, aPacket) {
+    ok(true, "tabNavigated event was fired after going forward.");
+    info("Still attached to the tab.");
+
+    gDebugger.addEventListener("Debugger:AfterScriptsAdded", function _onEvent(aEvent) {
+      gDebugger.removeEventListener(aEvent.type, _onEvent);
+
       executeSoon(function() {
         validateSecondPage();
         closeDebuggerAndFinish();
       });
     });
   });
 
   info("Going forward.");
--- a/browser/devtools/debugger/test/browser_dbg_location-changes-blank.js
+++ b/browser/devtools/debugger/test/browser_dbg_location-changes-blank.js
@@ -52,35 +52,34 @@ function testSimpleCall() {
   gDebuggee.simpleCall();
 }
 
 function testLocationChange()
 {
   gDebugger.DebuggerController.activeThread.resume(function() {
     gDebugger.DebuggerController.client.addOneTimeListener("tabNavigated", function(aEvent, aPacket) {
       ok(true, "tabNavigated event was fired.");
-      gDebugger.DebuggerController.client.addOneTimeListener("tabAttached", function(aEvent, aPacket) {
-        ok(true, "Successfully reattached to the tab again.");
+      info("Still attached to the tab.");
 
-        // Wait for the initial resume...
-        gDebugger.gClient.addOneTimeListener("resumed", function() {
-          is(gDebugger.DebuggerView.Scripts.selected, null,
-            "There should be no selected script.");
-          is(gDebugger.editor.getText().length, 0,
-            "The source editor not have any text displayed.");
+      gDebugger.addEventListener("Debugger:AfterScriptsAdded", function _onEvent(aEvent) {
+        gDebugger.removeEventListener(aEvent.type, _onEvent);
 
-          let menulist = gDebugger.DebuggerView.Scripts._scripts;
-          let noScripts = gDebugger.L10N.getStr("noScriptsText");
-          is(menulist.getAttribute("label"), noScripts,
-            "The menulist should display a notice that there are no scripts availalble.");
-          is(menulist.getAttribute("tooltiptext"), "",
-            "The menulist shouldn't have any tooltip text attributed when there are no scripts available.");
+        is(gDebugger.DebuggerView.Scripts.selected, null,
+          "There should be no selected script.");
+        is(gDebugger.editor.getText().length, 0,
+          "The source editor not have any text displayed.");
 
-          closeDebuggerAndFinish();
-        });
+        let menulist = gDebugger.DebuggerView.Scripts._scripts;
+        let noScripts = gDebugger.L10N.getStr("noScriptsText");
+        is(menulist.getAttribute("label"), noScripts,
+          "The menulist should display a notice that there are no scripts availalble.");
+        is(menulist.getAttribute("tooltiptext"), "",
+          "The menulist shouldn't have any tooltip text attributed when there are no scripts available.");
+
+        closeDebuggerAndFinish();
       });
     });
     content.location = "about:blank";
   });
 }
 
 registerCleanupFunction(function() {
   removeTab(gTab);
--- a/browser/devtools/debugger/test/browser_dbg_location-changes-new.js
+++ b/browser/devtools/debugger/test/browser_dbg_location-changes-new.js
@@ -52,35 +52,34 @@ function testSimpleCall() {
   gDebuggee.simpleCall();
 }
 
 function testLocationChange()
 {
   gDebugger.DebuggerController.activeThread.resume(function() {
     gDebugger.DebuggerController.client.addOneTimeListener("tabNavigated", function(aEvent, aPacket) {
       ok(true, "tabNavigated event was fired.");
-      gDebugger.DebuggerController.client.addOneTimeListener("tabAttached", function(aEvent, aPacket) {
-        ok(true, "Successfully reattached to the tab again.");
+      info("Still attached to the tab.");
 
-        // Wait for the initial resume...
-        gDebugger.gClient.addOneTimeListener("resumed", function() {
-          isnot(gDebugger.DebuggerView.Scripts.selected, null,
-            "There should be a selected script.");
-          isnot(gDebugger.editor.getText().length, 0,
-            "The source editor should have some text displayed.");
+      gDebugger.addEventListener("Debugger:AfterScriptsAdded", function _onEvent(aEvent) {
+        gDebugger.removeEventListener(aEvent.type, _onEvent);
 
-          let menulist = gDebugger.DebuggerView.Scripts._scripts;
-          let noScripts = gDebugger.L10N.getStr("noScriptsText");
-          isnot(menulist.getAttribute("label"), noScripts,
-            "The menulist should not display a notice that there are no scripts availalble.");
-          isnot(menulist.getAttribute("tooltiptext"), "",
-            "The menulist should have a tooltip text attributed.");
+        isnot(gDebugger.DebuggerView.Scripts.selected, null,
+          "There should be a selected script.");
+        isnot(gDebugger.editor.getText().length, 0,
+          "The source editor should have some text displayed.");
 
-          closeDebuggerAndFinish();
-        });
+        let menulist = gDebugger.DebuggerView.Scripts._scripts;
+        let noScripts = gDebugger.L10N.getStr("noScriptsText");
+        isnot(menulist.getAttribute("label"), noScripts,
+          "The menulist should not display a notice that there are no scripts availalble.");
+        isnot(menulist.getAttribute("tooltiptext"), "",
+          "The menulist should have a tooltip text attributed.");
+
+        closeDebuggerAndFinish();
       });
     });
     content.location = EXAMPLE_URL + "browser_dbg_iframes.html";
   });
 }
 
 registerCleanupFunction(function() {
   removeTab(gTab);
--- a/browser/devtools/debugger/test/browser_dbg_location-changes.js
+++ b/browser/devtools/debugger/test/browser_dbg_location-changes.js
@@ -47,21 +47,19 @@ function testSimpleCall() {
   gDebuggee.simpleCall();
 }
 
 function testLocationChange()
 {
   gDebugger.DebuggerController.activeThread.resume(function() {
     gDebugger.DebuggerController.client.addOneTimeListener("tabNavigated", function(aEvent, aPacket) {
       ok(true, "tabNavigated event was fired.");
-      gDebugger.DebuggerController.client.addOneTimeListener("tabAttached", function(aEvent, aPacket) {
-        ok(true, "Successfully reattached to the tab again.");
+      info("Still attached to the tab.");
 
-        closeDebuggerAndFinish();
-      });
+      closeDebuggerAndFinish();
     });
     content.location = TAB1_URL;
   });
 }
 
 registerCleanupFunction(function() {
   removeTab(gTab);
   gPane = null;
--- a/browser/devtools/webconsole/test/Makefile.in
+++ b/browser/devtools/webconsole/test/Makefile.in
@@ -19,16 +19,17 @@ MOCHITEST_BROWSER_FILES = \
 	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 \
 	browser_webconsole_execution_scope.js \
 	browser_webconsole_for_of.js \
 	browser_webconsole_history.js \
 	browser_webconsole_js_input_and_output_styling.js \
 	browser_webconsole_js_input_expansion.js \
 	browser_webconsole_live_filtering_of_message_types.js \
 	browser_webconsole_live_filtering_on_search_strings.js \
new file mode 100644
--- /dev/null
+++ b/browser/devtools/webconsole/test/browser_webconsole_change_font_size.js
@@ -0,0 +1,44 @@
+/* vim:set ts=2 sw=2 sts=2 et: */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ *
+ * Contributor(s):
+ *  Jennifer Fong <jfong@mozilla.com>
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+const TEST_URI = "http://example.com/";
+
+function test() {
+  addTab(TEST_URI);
+  browser.addEventListener("load", function onLoad() {
+    browser.removeEventListener("load", onLoad, true);
+    Services.prefs.setIntPref("devtools.webconsole.fontSize", 10);
+    openConsole(null, testFontSizeChange);
+  }, true);
+}
+
+function testFontSizeChange(hud) {
+  let inputNode = hud.jsterm.inputNode;
+  let outputNode = hud.jsterm.outputNode;
+  outputNode.focus();
+
+  EventUtils.synthesizeKey("-", { accelKey: true });
+  is(inputNode.style.fontSize, "10px", "input font stays at same size with ctrl+-");
+  is(outputNode.style.fontSize, inputNode.style.fontSize, "output font stays at same size with ctrl+-");
+
+  EventUtils.synthesizeKey("=", { accelKey: true });
+  is(inputNode.style.fontSize, "11px", "input font increased with ctrl+=");
+  is(outputNode.style.fontSize, inputNode.style.fontSize, "output font stays at same size with ctrl+=");
+
+  EventUtils.synthesizeKey("-", { accelKey: true });
+  is(inputNode.style.fontSize, "10px", "font decreased with ctrl+-");
+  is(outputNode.style.fontSize, inputNode.style.fontSize, "output font stays at same size with ctrl+-");
+
+  EventUtils.synthesizeKey("0", { accelKey: true });
+  is(inputNode.style.fontSize, "", "font reset with ctrl+0");
+  is(outputNode.style.fontSize, inputNode.style.fontSize, "output font stays at same size with ctrl+0");
+
+  finishTest();
+}
--- a/browser/devtools/webconsole/webconsole.js
+++ b/browser/devtools/webconsole/webconsole.js
@@ -147,16 +147,19 @@ const OUTPUT_INTERVAL = 50; // milliseco
 // When the output queue has more than MESSAGES_IN_INTERVAL items we throttle
 // output updates to this number of milliseconds. So during a lot of output we
 // update every N milliseconds given here.
 const THROTTLE_UPDATES = 1000; // milliseconds
 
 // The preference prefix for all of the Web Console filters.
 const FILTER_PREFS_PREFIX = "devtools.webconsole.filter.";
 
+// The minimum font size.
+const MIN_FONT_SIZE = 10;
+
 /**
  * A WebConsoleFrame instance is an interactive console initialized *per tab*
  * that displays console log data as well as provides an interactive terminal to
  * manipulate the current tab's document content.
  *
  * The WebConsoleFrame is responsible for the actual Web Console UI
  * implementation.
  *
@@ -313,21 +316,33 @@ WebConsoleFrame.prototype = {
    * @private
    */
   _initUI: function WCF__initUI()
   {
     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();
     this._initPositionUI();
     this._initFilterButtons();
 
+    let fontSize = Services.prefs.getIntPref("devtools.webconsole.fontSize");
+
+    if (fontSize != 0) {
+      fontSize = Math.max(MIN_FONT_SIZE, fontSize);
+
+      this.outputNode.style.fontSize = fontSize + "px";
+      this.completeNode.style.fontSize = fontSize + "px";
+      this.inputNode.style.fontSize = fontSize + "px";
+    }
+
     let saveBodies = doc.getElementById("saveBodies");
     saveBodies.addEventListener("command", function() {
       this.saveRequestAndResponseBodies = !this.saveRequestAndResponseBodies;
     }.bind(this));
     saveBodies.setAttribute("checked", this.saveRequestAndResponseBodies);
 
     let contextMenuId = this.outputNode.getAttribute("context");
     let contextMenu = doc.getElementById(contextMenuId);
@@ -507,16 +522,62 @@ WebConsoleFrame.prototype = {
       parentNode.replaceChild(oldOutputNode, this.outputNode);
       this.outputNode = oldOutputNode;
     }
 
     this.jsterm && this.jsterm.inputNode.focus();
   },
 
   /**
+   * 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.
+   */
+  changeFontSize: function WCF_changeFontSize(aSize)
+  {
+    let fontSize = this.window
+                   .getComputedStyle(this.outputNode, null)
+                   .getPropertyValue("font-size").replace("px", "");
+
+    if (this.outputNode.style.fontSize) {
+      fontSize = this.outputNode.style.fontSize.replace("px", "");
+    }
+
+    if (aSize == "+" || aSize == "-") {
+      fontSize = parseInt(fontSize, 10);
+
+      if (aSize == "+") {
+        fontSize += 1;
+      }
+      else {
+        fontSize -= 1;
+      }
+
+      if (fontSize < MIN_FONT_SIZE) {
+        fontSize = MIN_FONT_SIZE;
+      }
+
+      Services.prefs.setIntPref("devtools.webconsole.fontSize", fontSize);
+      fontSize = fontSize + "px";
+
+      this.completeNode.style.fontSize = fontSize;
+      this.inputNode.style.fontSize = fontSize;
+      this.outputNode.style.fontSize = fontSize;
+    }
+    else {
+      this.completeNode.style.fontSize = "";
+      this.inputNode.style.fontSize = "";
+      this.outputNode.style.fontSize = "";
+      Services.prefs.clearUserPref("devtools.webconsole.fontSize");
+    }
+  },
+
+  /**
    * Handler for all of the messages coming from the Web Console content script.
    *
    * @private
    * @param object aMessage
    *        A MessageManager object that holds the remote message.
    */
   receiveMessage: function WCF_receiveMessage(aMessage)
   {
@@ -3358,30 +3419,42 @@ CommandController.prototype = {
   },
 
   isCommandEnabled: function CommandController_isCommandEnabled(aCommand)
   {
     switch (aCommand) {
       case "cmd_copy":
         // Only enable "copy" if nodes are selected.
         return this.owner.outputNode.selectedCount > 0;
+      case "cmd_fontSizeEnlarge":
+      case "cmd_fontSizeReduce":
+      case "cmd_fontSizeReset":
       case "cmd_selectAll":
         return true;
     }
   },
 
   doCommand: function CommandController_doCommand(aCommand)
   {
     switch (aCommand) {
       case "cmd_copy":
         this.copy();
         break;
       case "cmd_selectAll":
         this.selectAll();
         break;
+      case "cmd_fontSizeEnlarge":
+        this.owner.changeFontSize("+");
+        break;
+      case "cmd_fontSizeReduce":
+        this.owner.changeFontSize("-");
+        break;
+      case "cmd_fontSizeReset":
+        this.owner.changeFontSize("");
+        break;
     }
   }
 };
 
 function gSequenceId()
 {
   return gSequenceId.n++;
 }
--- a/browser/devtools/webconsole/webconsole.xul
+++ b/browser/devtools/webconsole/webconsole.xul
@@ -13,16 +13,31 @@
 <window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
         title="&window.title;"
         windowtype="devtools:webconsole"
         persist="screenX screenY width height sizemode">
   <script type="text/javascript" src="chrome://global/content/globalOverlay.js"/>
   <script type="text/javascript" src="webconsole.js"/>
 
   <commandset id="editMenuCommands"/>
+
+  <commandset>
+    <command id="cmd_fullZoomEnlarge" oncommand="goDoCommand('cmd_fontSizeEnlarge');"/>
+    <command id="cmd_fullZoomReduce" oncommand="goDoCommand('cmd_fontSizeReduce');"/>
+    <command id="cmd_fullZoomReset" oncommand="goDoCommand('cmd_fontSizeReset');"/>
+  </commandset>
+  <keyset id="fontSizeChangeSet">
+    <key id="key_fullZoomReduce"  key="&fullZoomReduceCmd.commandkey;" command="cmd_fullZoomReduce"  modifiers="accel"/>
+    <key key="&fullZoomReduceCmd.commandkey2;"  command="cmd_fullZoomReduce" modifiers="accel"/>
+    <key id="key_fullZoomEnlarge" key="&fullZoomEnlargeCmd.commandkey;" command="cmd_fullZoomEnlarge" modifiers="accel"/>
+    <key key="&fullZoomEnlargeCmd.commandkey2;" command="cmd_fullZoomEnlarge" modifiers="accel"/>
+    <key key="&fullZoomEnlargeCmd.commandkey3;" command="cmd_fullZoomEnlarge" modifiers="accel"/>
+    <key id="key_fullZoomReset" key="&fullZoomResetCmd.commandkey;" command="cmd_fullZoomReset" modifiers="accel"/>
+    <key key="&fullZoomResetCmd.commandkey2;" command="cmd_fullZoomReset" modifiers="accel"/>
+  </keyset>
   <keyset id="editMenuKeys"/>
 
   <popupset id="mainPopupSet">
     <menupopup id="output-contextmenu">
       <menuitem id="saveBodies" type="checkbox" label="&saveBodies.label;"
                 accesskey="&saveBodies.accesskey;"/>
       <menuitem id="menu_copy"/>
       <menuitem id="menu_selectAll"/>
--- a/browser/locales/en-US/chrome/browser/devtools/webConsole.dtd
+++ b/browser/locales/en-US/chrome/browser/devtools/webConsole.dtd
@@ -73,8 +73,18 @@
 <!-- LOCALIZATION NOTE (positionMenu.window): When this option is selected the
   -  Web Console interface is displayed in a floating panel. -->
 <!ENTITY positionMenu.window   "Window">
 
 <!ENTITY filterBox.placeholder "Filter">
 <!ENTITY btnClear.label        "Clear">
 <!ENTITY btnClear.tooltip      "Clear the Web Console output">
 <!ENTITY btnClose.tooltip      "Close the Web Console">
+
+<!ENTITY fullZoomEnlargeCmd.commandkey  "+">
+<!ENTITY fullZoomEnlargeCmd.commandkey2 "="> <!-- + is above this key on many keyboards -->
+<!ENTITY fullZoomEnlargeCmd.commandkey3 "">
+
+<!ENTITY fullZoomReduceCmd.commandkey   "-">
+<!ENTITY fullZoomReduceCmd.commandkey2  "">
+
+<!ENTITY fullZoomResetCmd.commandkey    "0">
+<!ENTITY fullZoomResetCmd.commandkey2   "">
--- a/browser/themes/gnomestripe/devtools/webconsole.css
+++ b/browser/themes/gnomestripe/devtools/webconsole.css
@@ -13,17 +13,17 @@
 }
 
 /* General output styles */
 
 .webconsole-timestamp {
   color: GrayText;
   margin-top: 0;
   margin-bottom: 0;
-  font: 12px "DejaVu Sans Mono", monospace;
+  font-family: "DejaVu Sans Mono", monospace;
 }
 
 .hud-msg-node {
   list-style-image: url(chrome://browser/skin/devtools/webconsole.png);
   -moz-image-region: rect(0, 1px, 0, 0);
 }
 
 .webconsole-msg-icon {
@@ -38,17 +38,17 @@
 }
 
 .webconsole-msg-body {
   margin-top: 0;
   margin-bottom: 3px;
   -moz-margin-start: 3px;
   -moz-margin-end: 6px;
   white-space: pre-wrap;
-  font: 12px "DejaVu Sans Mono", monospace;
+  font-family: "DejaVu Sans Mono", monospace;
 }
 
 .webconsole-msg-body-piece {
   margin: 0;
 }
 
 .webconsole-msg-url {
   margin: 0 6px;
@@ -58,17 +58,17 @@
 .webconsole-msg-repeat {
   margin: 2px 0;
   padding-left: 4px;
   padding-right: 4px;
   color: white;
   background-color: red;
   border-radius: 40px;
   font: message-box;
-  font-size: 10px;
+  font-size: 0.9em;
   font-weight: 600;
 }
 
 /* TODO move this and other functional rules to content - bug 635359 */
 .webconsole-msg-repeat[value="1"] {
   display: none;
 }
 
@@ -92,24 +92,25 @@
 
 .hud-msg-node[selected="true"] > .webconsole-timestamp,
 .hud-msg-node[selected="true"] > .webconsole-location {
   color: inherit;
 }
 
 .jsterm-input-node,
 .jsterm-complete-node {
-  font: 12px "DejaVu Sans Mono", monospace;
+  font: 0.9em "DejaVu Sans Mono", monospace;
 }
 
 .hud-output-node {
   -moz-appearance: none;
   border-bottom: 1px solid ThreeDShadow;
   border-top: 1px solid ThreeDShadow;
   margin: 0;
+  font-size: 0.9em;
 }
 
 .hud-filtered-by-type,
 .hud-filtered-by-string {
   display: none;
 }
 
 .webconsole-clear-console-button > .toolbarbutton-icon {
@@ -209,46 +210,16 @@
   -moz-image-region: rect(24px, 48px, 32px, 40px);
 }
 
 .webconsole-close-button {
   list-style-image: url("moz-icon://stock/gtk-close?size=menu");
 }
 
 /* JSTerm Styles */
-
-.jsterm-wrapper-node {
-  font-family: monospace;
-  font-size: 1em;
-  background-color: #000;
-  border: 1px solid #333;
-  padding: 0.1em;
-  width: 100%;
-  height: 400px;
-}
-
-.jsterm-output-node {
-  width: 100%;
-  height: 400px;
-  color: white;
-  background-color: black;
-  overflow: auto;
-  overflow-x: auto;
-  position: absolute;
-  -moz-box-direction: reverse;
-}
-
-.jsterm-scroll-to-node {
-  height: 1px;
-  width: 1px;
-  position: relative;
-  top: 92%;
-  display: block;
-}
-
 .jsterm-input-node,
 .jsterm-complete-node {
   border: none;
   padding: 0 0 0 16px;
   -moz-appearance: none;
 }
 
 .jsterm-input-node {
@@ -259,12 +230,8 @@
 :-moz-any(.jsterm-input-node,
           .jsterm-complete-node) > .textbox-input-box > .textbox-textarea {
   overflow-x: hidden;
 }
 
 .jsterm-complete-node > .textbox-input-box > .textbox-textarea {
   color: GrayText;
 }
-
-.jsterm-output-line {
-  font-size: 1em;
-}
--- a/browser/themes/pinstripe/devtools/webconsole.css
+++ b/browser/themes/pinstripe/devtools/webconsole.css
@@ -15,17 +15,17 @@
 }
 
 /* General output styles */
 
 .webconsole-timestamp {
   color: GrayText;
   margin-top: 0;
   margin-bottom: 0;
-  font: 11px Menlo, Monaco, monospace;
+  font-family: Menlo, Monaco, monospace;
 }
 
 .hud-msg-node {
   list-style-image: url(chrome://browser/skin/devtools/webconsole.png);
   -moz-image-region: rect(0, 1px, 0, 0);
 }
 
 .webconsole-msg-icon {
@@ -40,17 +40,17 @@
 }
 
 .webconsole-msg-body {
   margin-top: 0;
   margin-bottom: 3px;
   -moz-margin-start: 3px;
   -moz-margin-end: 6px;
   white-space: pre-wrap;
-  font: 11px Menlo, Monaco, monospace;
+  font-family: Menlo, Monaco, monospace;
 }
 
 .webconsole-msg-body-piece {
   margin: 0;
 }
 
 .webconsole-msg-url {
   margin: 0 6px;
@@ -60,17 +60,17 @@
 .webconsole-msg-repeat {
   margin: 2px 0;
   padding-left: 4px;
   padding-right: 4px;
   color: white;
   background-color: red;
   border-radius: 40px;
   font: message-box;
-  font-size: 10px;
+  font-size: 0.9em;
   font-weight: 600;
 }
 
 /* TODO move this and other functional rules to content - bug 635359 */
 .webconsole-msg-repeat[value="1"] {
   display: none;
 }
 
@@ -85,17 +85,17 @@
 
 .hud-msg-node[selected="true"] > .webconsole-timestamp,
 .hud-msg-node[selected="true"] > .webconsole-location {
   color: inherit;
 }
 
 .jsterm-input-node,
 .jsterm-complete-node {
-  font: 11px Menlo, Monaco, monospace;
+  font: Menlo, Monaco, monospace;
 }
 
 .hud-output-node {
   -moz-appearance: none;
   border-bottom: 1px solid ThreeDShadow;
   border-top: 1px solid ThreeDShadow;
   margin: 0;
 }
@@ -277,46 +277,16 @@
   -moz-image-region: rect(0, 32px, 16px, 16px);
 }
 
 .webconsole-close-button:hover:active {
   -moz-image-region: rect(0, 48px, 16px, 32px);
 }
 
 /* JSTerm Styles */
-
-.jsterm-wrapper-node {
-  font-family: monospace;
-  font-size: 1em;
-  background-color: #000;
-  border: 1px solid #333;
-  padding: 0.1em;
-  width: 100%;
-  height: 400px;
-}
-
-.jsterm-output-node {
-  width: 100%;
-  height: 400px;
-  color: white;
-  background-color: black;
-  overflow: auto;
-  overflow-x: auto;
-  position: absolute;
-  -moz-box-direction: reverse;
-}
-
-.jsterm-scroll-to-node {
-  height: 1px;
-  width: 1px;
-  position: relative;
-  top: 92%;
-  display: block;
-}
-
 .jsterm-input-container {
   background: white;
 }
 
 .jsterm-input-node,
 .jsterm-complete-node {
   border: none;
   padding: 0 0 0 16px;
@@ -331,20 +301,16 @@
           .jsterm-complete-node) > .textbox-input-box > .textbox-textarea {
   overflow-x: hidden;
 }
 
 .jsterm-complete-node > .textbox-input-box > .textbox-textarea {
   color: GrayText;
 }
 
-.jsterm-output-line {
-  font-size: 1em;
-}
-
 .hud-console-filter-toolbar {
   background: @scopeBarBackground@;
   border-bottom: @scopeBarSeparatorBorder@;
   padding: 0px 1px;
   -moz-appearance: none;
   -moz-box-align: center;
 }
 
--- a/browser/themes/winstripe/devtools/webconsole.css
+++ b/browser/themes/winstripe/devtools/webconsole.css
@@ -13,17 +13,17 @@
 }
 
 /* General output styles */
 
 .webconsole-timestamp {
   color: GrayText;
   margin-top: 0;
   margin-bottom: 0;
-  font: 12px Consolas, Lucida Console, monospace;
+  font-family: Consolas, Lucida Console, monospace;
 }
 
 .hud-msg-node {
   list-style-image: url(chrome://browser/skin/devtools/webconsole.png);
   -moz-image-region: rect(0, 1px, 0, 0);
 }
 
 .webconsole-msg-icon {
@@ -38,17 +38,17 @@
 }
 
 .webconsole-msg-body {
   margin-top: 0;
   margin-bottom: 3px;
   -moz-margin-start: 3px;
   -moz-margin-end: 6px;
   white-space: pre-wrap;
-  font: 12px Consolas, Lucida Console, monospace;
+  font-family: Consolas, Lucida Console, monospace;
 }
 
 .webconsole-msg-body-piece {
   margin: 0;
 }
 
 .webconsole-msg-url {
   margin: 0 6px;
@@ -58,17 +58,17 @@
 .webconsole-msg-repeat {
   margin: 2px 0;
   padding-left: 4px;
   padding-right: 4px;
   color: white;
   background-color: red;
   border-radius: 40px;
   font: message-box;
-  font-size: 10px;
+  font-size: 0.9em;
   font-weight: 600;
 }
 
 /* TODO move this and other functional rules to content - bug 635359 */
 .webconsole-msg-repeat[value="1"] {
   display: none;
 }
 
@@ -83,17 +83,17 @@
 
 .hud-msg-node[selected="true"] > .webconsole-timestamp,
 .hud-msg-node[selected="true"] > .webconsole-location {
   color: inherit;
 }
 
 .jsterm-input-node,
 .jsterm-complete-node {
-  font: 12px Consolas, Lucida Console, monospace;
+  font-family: Consolas, Lucida Console, monospace;
 }
 
 .hud-output-node {
   -moz-appearance: none;
   border-bottom: 1px solid ThreeDShadow;
   border-top: 1px solid ThreeDShadow;
   margin: 0;
 }
@@ -227,46 +227,16 @@
   -moz-image-region: rect(0, 32px, 16px, 16px);
 }
 
 .webconsole-close-button:hover:active {
   -moz-image-region: rect(0, 48px, 16px, 32px);
 }
 
 /* JSTerm Styles */
-
-.jsterm-wrapper-node {
-  font-family: monospace;
-  font-size: 1em;
-  background-color: #000;
-  border: 1px solid #333;
-  padding: 0.1em;
-  width: 100%;
-  height: 400px;
-}
-
-.jsterm-output-node {
-  width: 100%;
-  height: 400px;
-  color: white;
-  background-color: black;
-  overflow: auto;
-  overflow-x: auto;
-  position: absolute;
-  -moz-box-direction: reverse;
-}
-
-.jsterm-scroll-to-node {
-  height: 1px;
-  width: 1px;
-  position: relative;
-  top: 92%;
-  display: block;
-}
-
 .jsterm-input-node,
 .jsterm-complete-node {
   border: none;
   padding: 0 0 0 16px;
   -moz-appearance: none;
 }
 
 .jsterm-input-node {
@@ -277,19 +247,15 @@
           .jsterm-complete-node) > .textbox-input-box > .textbox-textarea {
   overflow-x: hidden;
 }
 
 .jsterm-complete-node > .textbox-input-box > .textbox-textarea {
   color: GrayText;
 }
 
-.jsterm-output-line {
-  font-size: 1em;
-}
-
 .hud-console-filter-toolbar {
   padding: 1px 2px;
   -moz-box-align: center;
   -moz-appearance: none;
   background-color: -moz-dialog;
   border-top: none;
 }
--- a/build/pymake/pymake/process.py
+++ b/build/pymake/pymake/process.py
@@ -1,15 +1,15 @@
 """
 Skipping shell invocations is good, when possible. This wrapper around subprocess does dirty work of
 parsing command lines into argv and making sure that no shell magic is being used.
 """
 
 #TODO: ship pyprocessing?
-import multiprocessing, multiprocessing.dummy
+import multiprocessing
 import subprocess, shlex, re, logging, sys, traceback, os, imp, glob
 # XXXkhuey Work around http://bugs.python.org/issue1731717
 subprocess._cleanup = lambda: None
 import command, util
 if sys.platform=='win32':
     import win32process
 
 _log = logging.getLogger('pymake.process')
@@ -155,24 +155,37 @@ class PopenJob(Job):
     """
     def __init__(self, argv, executable, shell, env, cwd):
         Job.__init__(self)
         self.argv = argv
         self.executable = executable
         self.shell = shell
         self.env = env
         self.cwd = cwd
+        self.parentpid = os.getpid()
 
     def run(self):
+        assert os.getpid() != self.parentpid
+        # subprocess.Popen doesn't use the PATH set in the env argument for
+        # finding the executable on some platforms (but strangely it does on
+        # others!), so set os.environ['PATH'] explicitly. This is parallel-
+        # safe because pymake uses separate processes for parallelism, and
+        # each process is serial. See http://bugs.python.org/issue8557 for a
+        # general overview of "subprocess PATH semantics and portability".
+        oldpath = os.environ['PATH']
         try:
+            if self.env is not None and self.env.has_key('PATH'):
+                os.environ['PATH'] = self.env['PATH']
             p = subprocess.Popen(self.argv, executable=self.executable, shell=self.shell, env=self.env, cwd=self.cwd)
             return p.wait()
         except OSError, e:
             print >>sys.stderr, e
             return -127
+        finally:
+            os.environ['PATH'] = oldpath
 
 class PythonException(Exception):
     def __init__(self, message, exitcode):
         Exception.__init__(self)
         self.message = message
         self.exitcode = exitcode
 
     def __str__(self):
@@ -200,18 +213,20 @@ class PythonJob(Job):
     """
     def __init__(self, module, method, argv, env, cwd, pycommandpath=None):
         self.module = module
         self.method = method
         self.argv = argv
         self.env = env
         self.cwd = cwd
         self.pycommandpath = pycommandpath or []
+        self.parentpid = os.getpid()
 
     def run(self):
+        assert os.getpid() != self.parentpid
         # os.environ is a magic dictionary. Setting it to something else
         # doesn't affect the environment of subprocesses, so use clear/update
         oldenv = dict(os.environ)
         try:
             os.chdir(self.cwd)
             os.environ.clear()
             os.environ.update(self.env)
             if self.module not in sys.modules:
@@ -261,28 +276,25 @@ class ParallelContext(object):
     _allcontexts = set()
     _condition = multiprocessing.Condition()
 
     def __init__(self, jcount):
         self.jcount = jcount
         self.exit = False
 
         self.processpool = multiprocessing.Pool(processes=jcount)
-        self.threadpool = multiprocessing.dummy.Pool(processes=jcount)
         self.pending = [] # list of (cb, args, kwargs)
         self.running = [] # list of (subprocess, cb)
 
         self._allcontexts.add(self)
 
     def finish(self):
         assert len(self.pending) == 0 and len(self.running) == 0, "pending: %i running: %i" % (len(self.pending), len(self.running))
         self.processpool.close()
-        self.threadpool.close()
         self.processpool.join()
-        self.threadpool.join()
         self._allcontexts.remove(self)
 
     def run(self):
         while len(self.pending) and len(self.running) < self.jcount:
             cb, args, kwargs = self.pending.pop(0)
             cb(*args, **kwargs)
 
     def defer(self, cb, *args, **kwargs):
@@ -300,17 +312,17 @@ class ParallelContext(object):
         self.running.append((job, cb))
 
     def call(self, argv, shell, env, cwd, cb, echo, justprint=False, executable=None):
         """
         Asynchronously call the process
         """
 
         job = PopenJob(argv, executable=executable, shell=shell, env=env, cwd=cwd)
-        self.defer(self._docall_generic, self.threadpool, job, cb, echo, justprint)
+        self.defer(self._docall_generic, self.processpool, job, cb, echo, justprint)
 
     def call_native(self, module, method, argv, env, cwd, cb,
                     echo, justprint=False, pycommandpath=None):
         """
         Asynchronously call the native function
         """
 
         job = PythonJob(module, method, argv, env, cwd, pycommandpath)
new file mode 100755
--- /dev/null
+++ b/build/pymake/tests/pathdir/pathtest
@@ -0,0 +1,2 @@
+#!/bin/sh
+echo Called shell script: 2f7cdd0b-7277-48c1-beaf-56cb0dbacb24
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..3178db9a94feb04bfddc0cf0ff75cf9aa1c7a20f
GIT binary patch
literal 45056
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
A=Kufz
new file mode 100644
--- /dev/null
+++ b/build/pymake/tests/pathdir/src/Makefile
@@ -0,0 +1,2 @@
+pathtest.exe: pathtest.cpp
+	cl -EHsc -MT $^
new file mode 100644
--- /dev/null
+++ b/build/pymake/tests/pathdir/src/pathtest.cpp
@@ -0,0 +1,6 @@
+#include <cstdio>
+
+int main() {
+  std::printf("Called Windows executable: 2f7cdd0b-7277-48c1-beaf-56cb0dbacb24\n");
+  return 0;
+}
new file mode 100644
--- /dev/null
+++ b/build/pymake/tests/subprocess-path.mk
@@ -0,0 +1,32 @@
+#T gmake skip
+#T grep-for: "2f7cdd0b-7277-48c1-beaf-56cb0dbacb24"
+
+ifdef __WIN32__
+PS:=;
+else
+PS:=:
+endif
+
+export PATH := $(TESTPATH)/pathdir$(PS)$(PATH)
+
+# Test two commands. The first one shouldn't go through the shell and the
+# second one should. The pathdir subdirectory has a Windows executable called
+# pathtest.exe and a shell script called pathtest. We don't care which one is
+# run, just that one of the two is (we use a uuid + grep-for to make sure
+# that happens).
+#
+# FAQ:
+# Q. Why skip GNU Make?
+# A. Because $(TESTPATH) is a Windows-style path, and MSYS make doesn't take
+#    too kindly to Windows paths in the PATH environment variable.
+#
+# Q. Why use an exe and not a batch file?
+# A. The use cases here were all exe files without the extension. Batch file
+#    lookup has broken semantics if the .bat extension isn't passed.
+#
+# Q. Why are the commands silent?
+# A. So that we don't pass the grep-for test by mistake.
+all:
+	@pathtest
+	@pathtest | grep -q 2f7cdd0b-7277-48c1-beaf-56cb0dbacb24
+	@echo TEST-PASS
--- a/toolkit/devtools/debugger/dbg-client.jsm
+++ b/toolkit/devtools/debugger/dbg-client.jsm
@@ -173,16 +173,27 @@ const ThreadStateTypes = {
  */
 const UnsolicitedNotifications = {
   "newScript": "newScript",
   "tabDetached": "tabDetached",
   "tabNavigated": "tabNavigated"
 };
 
 /**
+ * Set of pause types that are sent by the server and not as an immediate
+ * response to a client request.
+ */
+const UnsolicitedPauses = {
+  "resumeLimit": "resumeLimit",
+  "debuggerStatement": "debuggerStatement",
+  "breakpoint": "breakpoint",
+  "watchpoint": "watchpoint"
+};
+
+/**
  * Set of debug protocol request types that specify the protocol request being
  * sent to the server.
  */
 const DebugProtocolTypes = {
   "assign": "assign",
   "attach": "attach",
   "clientEvaluate": "clientEvaluate",
   "delete": "delete",
@@ -395,28 +406,38 @@ DebuggerClient.prototype = {
     try {
       if (!aPacket.from) {
         Cu.reportError("Server did not specify an actor, dropping packet: " +
                        JSON.stringify(aPacket));
         return;
       }
 
       let onResponse;
-      // Don't count unsolicited notifications as responses.
+      // Don't count unsolicited notifications or pauses as responses.
       if (aPacket.from in this._activeRequests &&
-          !(aPacket.type in UnsolicitedNotifications)) {
+          !(aPacket.type in UnsolicitedNotifications) &&
+          !(aPacket.type == ThreadStateTypes.paused &&
+            aPacket.why.type in UnsolicitedPauses)) {
         onResponse = this._activeRequests[aPacket.from].onResponse;
         delete this._activeRequests[aPacket.from];
       }
 
-      // paused/resumed/detached get special treatment...
+      // Packets that indicate thread state changes get special treatment.
       if (aPacket.type in ThreadStateTypes &&
           aPacket.from in this._threadClients) {
         this._threadClients[aPacket.from]._onThreadState(aPacket);
       }
+      // On navigation the server resumes, so the client must resume as well.
+      // We achive that by generating a fake resumption packet that triggers
+      // the client's thread state change listeners.
+      if (aPacket.type == UnsolicitedNotifications.tabNavigated &&
+          aPacket.from in this._tabClients) {
+        let resumption = { from: this.activeThread._actor, type: "resumed" };
+        this.activeThread._onThreadState(resumption);
+      }
       this.notify(aPacket.type, aPacket);
 
       if (onResponse) {
         onResponse(aPacket);
       }
     } catch(ex) {
       dumpn("Error handling response: " + ex + " - stack:\n" + ex.stack);
       Cu.reportError(ex);
@@ -720,22 +741,30 @@ ThreadClient.prototype = {
    * @param aOnResponse integer
    *        Called with the thread's response.
    */
   getScripts: function TC_getScripts(aOnResponse) {
     let packet = { to: this._actor, type: DebugProtocolTypes.scripts };
     this._client.request(packet, aOnResponse);
   },
 
-  /**
-   * A cache of source scripts. Clients can observe the scriptsadded and
-   * scriptscleared event to keep up to date on changes to this cache,
-   * and can fill it using the fillScripts method.
-   */
-  get cachedScripts() { return this._scriptCache; },
+  _doInterrupted: function TC_doInterrupted(aAction, aError) {
+    if (this.paused) {
+      aAction();
+      return;
+    }
+    this.interrupt(function(aResponse) {
+      if (aResponse) {
+        aError(aResponse);
+        return;
+      }
+      aAction();
+      this.resume(function() {});
+    }.bind(this));
+  },
 
   /**
    * Ensure that source scripts have been loaded in the
    * ThreadClient's source script cache. A scriptsadded event will be
    * sent when the source script cache is updated.
    *
    * @returns true if a scriptsadded notification should be expected.
    */
--- a/toolkit/devtools/debugger/server/dbg-browser-actors.js
+++ b/toolkit/devtools/debugger/server/dbg-browser-actors.js
@@ -441,20 +441,29 @@ BrowserTabActor.prototype = {
   onWindowCreated: function BTA_onWindowCreated(evt) {
     if (evt.target === this.browser.contentDocument) {
       // pageshow events for non-persisted pages have already been handled by a
       // prior DOMWindowCreated event.
       if (evt.type == "pageshow" && !evt.persisted) {
         return;
       }
       if (this._attached) {
+        this.threadActor.clearDebuggees();
+        this.threadActor.dbg.enabled = true;
+        if (this._progressListener) {
+          delete this._progressListener._needsTabNavigated;
+        }
         this.conn.send({ from: this.actorID, type: "tabNavigated",
                          url: this.browser.contentDocument.URL });
       }
     }
+
+    if (this._attached) {
+      this._addDebuggees(evt.target.defaultView.wrappedJSObject);
+    }
   }
 };
 
 /**
  * The request types this actor can handle.
  */
 BrowserTabActor.prototype.requestTypes = {
   "attach": BrowserTabActor.prototype.onAttach,
@@ -494,20 +503,23 @@ DebuggerProgressListener.prototype = {
       }
 
       // If the debuggee is not paused, then proceed normally.
       if (this._tabActor.threadActor.state != "paused") {
         return;
       }
 
       aRequest.suspend();
+      this._tabActor.threadActor.onResume();
+      this._tabActor.threadActor.dbg.enabled = false;
       this._tabActor._pendingNavigation = aRequest;
-      this._tabActor._detach();
       this._needsTabNavigated = true;
     } else if (isStop && isWindow && isNetwork && this._needsTabNavigated) {
+      delete this._needsTabNavigated;
+      this._tabActor.threadActor.dbg.enabled = true;
       this._tabActor.conn.send({
         from: this._tabActor.actorID,
         type: "tabNavigated",
         url: this._tabActor.browser.contentDocument.URL
       });
 
       this.destroy();
     }
--- a/toolkit/devtools/debugger/server/dbg-script-actors.js
+++ b/toolkit/devtools/debugger/server/dbg-script-actors.js
@@ -46,35 +46,56 @@ ThreadActor.prototype = {
   get threadLifetimePool() {
     if (!this._threadLifetimePool) {
       this._threadLifetimePool = new ActorPool(this.conn);
       this.conn.addActorPool(this._threadLifetimePool);
     }
     return this._threadLifetimePool;
   },
 
+  clearDebuggees: function TA_clearDebuggees() {
+    if (this._dbg) {
+      let debuggees = this._dbg.getDebuggees();
+      for (let debuggee of debuggees) {
+        this._dbg.removeDebuggee(debuggee);
+      }
+    }
+    this.conn.removeActorPool(this._threadLifetimePool || undefined);
+    this._threadLifetimePool = null;
+    // Unless we carefully take apart the scripts table this way, we end up
+    // leaking documents. It would be nice to track this down carefully, once
+    // we have the appropriate tools.
+    for (let url in this._scripts) {
+      delete this._scripts[url];
+    }
+    this._scripts = {};
+  },
+
   /**
    * Add a debuggee global to the Debugger object.
    */
   addDebuggee: function TA_addDebuggee(aGlobal) {
     // Use the inspector xpcom component to turn on debugging
     // for aGlobal's compartment.  Ideally this won't be necessary
     // medium- to long-term, and will be managed by the engine
     // instead.
 
     if (!this._dbg) {
       this._dbg = new Debugger();
+      this._dbg.uncaughtExceptionHook = this.uncaughtExceptionHook.bind(this);
+      this._dbg.onDebuggerStatement = this.onDebuggerStatement.bind(this);
+      this._dbg.onNewScript = this.onNewScript.bind(this);
+      // Keep the debugger disabled until a client attaches.
+      this.dbg.enabled = this._state != "detached";
     }
 
     this.dbg.addDebuggee(aGlobal);
-    this.dbg.uncaughtExceptionHook = this.uncaughtExceptionHook.bind(this);
-    this.dbg.onDebuggerStatement = this.onDebuggerStatement.bind(this);
-    this.dbg.onNewScript = this.onNewScript.bind(this);
-    // Keep the debugger disabled until a client attaches.
-    this.dbg.enabled = false;
+    for (let s of this.dbg.findScripts()) {
+      this._addScript(s);
+    }
   },
 
   /**
    * Remove a debuggee global from the JSInspector.
    */
   removeDebugee: function TA_removeDebuggee(aGlobal) {
     try {
       this.dbg.removeDebuggee(aGlobal);
@@ -85,29 +106,24 @@ ThreadActor.prototype = {
   },
 
   disconnect: function TA_disconnect() {
     if (this._state == "paused") {
       this.onResume();
     }
 
     this._state = "exited";
-    if (this.dbg) {
-      this.dbg.enabled = false;
-      this._dbg = null;
+
+    this.clearDebuggees();
+
+    if (!this._dbg) {
+      return;
     }
-    this.conn.removeActorPool(this._threadLifetimePool || undefined);
-    this._threadLifetimePool = null;
-    // Unless we carefully take apart the scripts table this way, we end up
-    // leaking documents. It would be nice to track this down carefully, once
-    // we have the appropriate tools.
-    for (let url in this._scripts) {
-      delete this._scripts[url];
-    }
-    this._scripts = {};
+    this._dbg.enabled = false;
+    this._dbg = null;
   },
 
   /**
    * Disconnect the debugger and put the actor in the exited state.
    */
   exit: function TA_exit() {
     this.disconnect();
   },
--- a/toolkit/devtools/debugger/server/dbg-server.js
+++ b/toolkit/devtools/debugger/server/dbg-server.js
@@ -361,17 +361,20 @@ DebuggerServerConnection.prototype = {
   addActorPool: function DSC_addActorPool(aActorPool) {
     this._extraPools.push(aActorPool);
   },
 
   /**
    * Remove a previously-added pool of actors to the connection.
    */
   removeActorPool: function DSC_removeActorPool(aActorPool) {
-    let index = this._extraPools.splice(this._extraPools.lastIndexOf(aActorPool), 1);
+    let index = this._extraPools.lastIndexOf(aActorPool);
+    if (index > -1) {
+      this._extraPools.splice(index, 1);
+    }
   },
 
   /**
    * Add an actor to the default actor pool for this connection.
    */
   addActor: function DSC_addActor(aActor) {
     this._actorPool.addActor(aActor);
   },