merge m-c to fx-team
authorTim Taubert <tim.taubert@gmx.de>
Wed, 06 Jun 2012 17:40:11 +0200
changeset 95957 7f6e0921d3c8142cd7041585ff0ca765c06b7e9e
parent 95952 3df1de4c95927e43bb2fd4ee688fe74bbdbb4be2 (current diff)
parent 95956 e767617a00037e77fbecfff2096c1eb76f81f31a (diff)
child 95958 e5b003aaf179d4c824aac5587098826ccb9ab167
child 95995 484f9e22295db88a5636e1df4457a7b529810882
child 96177 f88227ac42f8e7b90c48c8bce860257fa6096ea4
push id22861
push usertim.taubert@gmx.de
push dateWed, 06 Jun 2012 15:40:49 +0000
treeherdermozilla-central@7f6e0921d3c8 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone16.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
--- a/browser/components/sessionstore/content/aboutSessionRestore.xhtml
+++ b/browser/components/sessionstore/content/aboutSessionRestore.xhtml
@@ -66,28 +66,28 @@
             <treechildren flex="1"/>
           </tree>
         </div>
       </div>
 
       <!-- Buttons -->
       <hbox xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" id="buttons">
 #ifdef XP_UNIX
-        <button id="errorCancel" label="&restorepage.cancelButton;"
-                accesskey="&restorepage.cancel.access;"
+        <button id="errorCancel" label="&restorepage.closeButton;"
+                accesskey="&restorepage.close.access;"
                 oncommand="startNewSession();"/>
         <button id="errorTryAgain" label="&restorepage.tryagainButton;"
                 accesskey="&restorepage.restore.access;"
                 oncommand="restoreSession();"/>
 #else
         <button id="errorTryAgain" label="&restorepage.tryagainButton;"
                 accesskey="&restorepage.restore.access;"
                 oncommand="restoreSession();"/>
-        <button id="errorCancel" label="&restorepage.cancelButton;"
-                accesskey="&restorepage.cancel.access;"
+        <button id="errorCancel" label="&restorepage.closeButton;"
+                accesskey="&restorepage.close.access;"
                 oncommand="startNewSession();"/>
 #endif
       </hbox>
       <!-- holds the session data for when the tab is closed -->
       <input type="text" id="sessionData" style="display: none;"/>
     </div>
 
   </body>
--- a/browser/devtools/debugger/debugger-controller.js
+++ b/browser/devtools/debugger/debugger-controller.js
@@ -118,24 +118,33 @@ let DebuggerController = {
     }
 
     // If this debugger is connecting remotely to a server, we need to check
     // after a while if the connection actually succeeded.
     this._remoteConnectionTry = ++this._remoteConnectionTry || 1;
     this._remoteConnectionTimeout = window.setTimeout(function() {
       // If we couldn't connect to any server yet, try again...
       if (!DebuggerController.activeThread) {
+        DebuggerController._onRemoteConnectionTimeout();
         DebuggerController._connect();
       }
     }, Prefs.remoteTimeout);
 
     return true;
   },
 
   /**
+   * Called when a remote connection timeout occurs.
+   */
+  _onRemoteConnectionTimeout: function DC__onRemoteConnectionTimeout() {
+    Cu.reportError("Couldn't connect to " +
+      Prefs.remoteHost + ":" + Prefs.remotePort);
+  },
+
+  /**
    * Initializes a debugger client and connects it to the debugger server,
    * wiring event handlers as necessary.
    */
   _connect: function DC__connect() {
     if (this._isRemoteDebugger) {
       if (!this._prepareConnection()) {
         return;
       }
@@ -912,102 +921,150 @@ SourceScripts.prototype = {
         DebuggerView.editor.setMode(SourceEditor.MODES.JAVASCRIPT);
       } else {
         DebuggerView.editor.setMode(SourceEditor.MODES.HTML);
       }
       return;
     }
 
     // Use JS mode for files with .js and .jsm extensions.
-    if (/\.jsm?$/.test(this._trimUrlQuery(aUrl))) {
+    if (/\.jsm?$/.test(this.trimUrlQuery(aUrl))) {
       DebuggerView.editor.setMode(SourceEditor.MODES.JAVASCRIPT);
     } else {
       DebuggerView.editor.setMode(SourceEditor.MODES.HTML);
     }
   },
 
   /**
-   * Trims the id selector or query part of a url string, if necessary.
+   * Trims the query part or reference identifier of a url string, if necessary.
    *
    * @param string aUrl
    *        The script url.
    * @return string
+   *         The url with the trimmed query.
    */
-  _trimUrlQuery: function SS__trimUrlQuery(aUrl) {
-    let q = aUrl.indexOf('#');
-    if (q === -1) q = aUrl.indexOf('?');
-    if (q === -1) q = aUrl.indexOf('&');
+  trimUrlQuery: function SS_trimUrlQuery(aUrl) {
+    let length = aUrl.length;
+    let q1 = aUrl.indexOf('?');
+    let q2 = aUrl.indexOf('&');
+    let q3 = aUrl.indexOf('#');
+    let q = Math.min(q1 !== -1 ? q1 : length,
+                     q2 !== -1 ? q2 : length,
+                     q3 !== -1 ? q3 : length);
 
-    if (q > -1) {
-      return aUrl.slice(0, q);
-    }
-    return aUrl;
+    return aUrl.slice(0, q);
   },
 
   /**
-   * Gets the prePath for a script URL.
+   * Trims as much as possible from a URL, while keeping the result unique
+   * in the Debugger View scripts container.
    *
-   * @param string aUrl
-   *        The script url.
+   * @param string | nsIURL aUrl
+   *        The script URL.
+   * @param string aLabel [optional]
+   *        The resulting label at each step.
+   * @param number aSeq [optional]
+   *        The current iteration step.
    * @return string
-   *         The script prePath if the url is valid, null otherwise.
+   *         The resulting label at the final step.
    */
-  _getScriptPrePath: function SS__getScriptDomain(aUrl) {
-    try {
-      return Services.io.newURI(aUrl, null, null).prePath + "/";
-    } catch (e) {
+  _trimURL: function SS__trimURL(aUrl, aLabel, aSeq) {
+    if (!(aUrl instanceof Ci.nsIURL)) {
+      try {
+        // Use an nsIURL to parse all the url path parts.
+        aUrl = Services.io.newURI(aUrl, null, null).QueryInterface(Ci.nsIURL);
+      } catch (e) {
+        // This doesn't look like a url, or nsIURL can't handle it.
+        return aUrl;
+      }
+    }
+    if (!aSeq) {
+      let name = aUrl.fileName;
+      if (name) {
+        // This is a regular file url, get only the file name (contains the
+        // base name and extension if available).
+
+        // If this url contains an invalid query, unfortunately nsIURL thinks
+        // it's part of the file extension. It must be removed.
+        aLabel = aUrl.fileName.replace(/\&.*/, "");
+      } else {
+        // This is not a file url, hence there is no base name, nor extension.
+        // Proceed using other available information.
+        aLabel = "";
+      }
+      aSeq = 1;
+    }
+
+    // If we have a label and it doesn't start with a query...
+    if (aLabel && aLabel.indexOf("?") !== 0) {
+
+      if (DebuggerView.Scripts.containsIgnoringQuery(aUrl.spec)) {
+        // A page may contain multiple requests to the same url but with different
+        // queries. It would be redundant to show each one.
+        return aLabel;
+      }
+      if (!DebuggerView.Scripts.containsLabel(aLabel)) {
+        // We found the shortest unique label for the url.
+        return aLabel;
+      }
     }
-    return null;
+
+    // Append the url query.
+    if (aSeq === 1) {
+      let query = aUrl.query;
+      if (query) {
+        return this._trimURL(aUrl, aLabel + "?" + query, aSeq + 1);
+      }
+      aSeq++;
+    }
+    // Append the url reference.
+    if (aSeq === 2) {
+      let ref = aUrl.ref;
+      if (ref) {
+        return this._trimURL(aUrl, aLabel + "#" + aUrl.ref, aSeq + 1);
+      }
+      aSeq++;
+    }
+    // Prepend the url directory.
+    if (aSeq === 3) {
+      let dir = aUrl.directory;
+      if (dir) {
+        return this._trimURL(aUrl, dir.replace(/^\//, "") + aLabel, aSeq + 1);
+      }
+      aSeq++;
+    }
+    // Prepend the hostname and port number.
+    if (aSeq === 4) {
+      let host = aUrl.hostPort;
+      if (host) {
+        return this._trimURL(aUrl, host + "/" + aLabel, aSeq + 1);
+      }
+      aSeq++;
+    }
+    // Use the whole url spec but ignoring the reference.
+    if (aSeq === 5) {
+      return this._trimURL(aUrl, aUrl.specIgnoringRef, aSeq + 1);
+    }
+    // Give up.
+    return aUrl.spec;
   },
 
   /**
    * Gets a unique, simplified label from a script url.
-   * ex: a). ici://some.address.com/random/subrandom/
-   *     b). ni://another.address.org/random/subrandom/page.html
-   *     c). san://interesting.address.gro/random/script.js
-   *     d). si://interesting.address.moc/random/another/script.js
-   * =>
-   *     a). subrandom/
-   *     b). page.html
-   *     c). script.js
-   *     d). another/script.js
    *
    * @param string aUrl
    *        The script url.
    * @param string aHref
    *        The content location href to be used. If unspecified, it will
    *        default to the script url prepath.
    * @return string
    *         The simplified label.
    */
   _getScriptLabel: function SS__getScriptLabel(aUrl, aHref) {
-    let url = this._trimUrlQuery(aUrl);
-
-    if (this._labelsCache[url]) {
-      return this._labelsCache[url];
-    }
-
-    let content = window.parent.content;
-    let domain = content ? content.location.href : this._getScriptPrePath(aUrl);
-
-    let href = aHref || domain;
-    let pathElements = url.split("/");
-    let label = pathElements.pop() || (pathElements.pop() + "/");
-
-    // If the label as a leaf name is already present in the scripts list.
-    if (DebuggerView.Scripts.containsLabel(label)) {
-      label = url.replace(href.substring(0, href.lastIndexOf("/") + 1), "");
-
-      // If the path/to/script is exactly the same, we're in different domains.
-      if (DebuggerView.Scripts.containsLabel(label)) {
-        label = url;
-      }
-    }
-
-    return this._labelsCache[url] = label;
+    return this._labelsCache[aUrl] || (this._labelsCache[aUrl] = this._trimURL(aUrl));
   },
 
   /**
    * Clears the labels cache, populated by SS_getScriptLabel.
    * This should be done every time the content location changes.
    */
   _clearLabelsCache: function SS__clearLabelsCache() {
     this._labelsCache = {};
--- a/browser/devtools/debugger/debugger-view.js
+++ b/browser/devtools/debugger/debugger-view.js
@@ -154,16 +154,41 @@ ScriptsView.prototype = {
    */
   clearSearch: function DVS_clearSearch() {
     this._searchbox.value = "";
     this._onScriptsSearch({});
   },
 
   /**
    * Checks whether the script with the specified URL is among the scripts
+   * known to the debugger (ignoring the query & reference).
+   *
+   * @param string aUrl
+   *        The script URL.
+   * @return boolean
+   */
+  containsIgnoringQuery: function DVS_containsIgnoringQuery(aUrl) {
+    let sourceScripts = DebuggerController.SourceScripts;
+    aUrl = sourceScripts.trimUrlQuery(aUrl);
+
+    if (this._tmpScripts.some(function(element) {
+      return sourceScripts.trimUrlQuery(element.script.url) == aUrl;
+    })) {
+      return true;
+    }
+    if (this.scriptLocations.some(function(url) {
+      return sourceScripts.trimUrlQuery(url) == aUrl;
+    })) {
+      return true;
+    }
+    return false;
+  },
+
+  /**
+   * Checks whether the script with the specified URL is among the scripts
    * known to the debugger and shown in the list.
    *
    * @param string aUrl
    *        The script URL.
    * @return boolean
    */
   contains: function DVS_contains(aUrl) {
     if (this._tmpScripts.some(function(element) {
@@ -341,17 +366,17 @@ ScriptsView.prototype = {
    * @param boolean aSelectIfEmptyFlag
    *        True to set the newly created script as the currently selected item
    *        if there are no other existing scripts in the container.
    */
   _createScriptElement: function DVS__createScriptElement(
     aLabel, aScript, aIndex, aSelectIfEmptyFlag)
   {
     // Make sure we don't duplicate anything.
-    if (aLabel == "null" || this.containsLabel(aLabel)) {
+    if (aLabel == "null" || this.containsLabel(aLabel) || this.contains(aScript.url)) {
       return;
     }
 
     let scriptItem =
       aIndex == -1 ? this._scripts.appendItem(aLabel, aScript.url)
                    : this._scripts.insertItemAt(aIndex, aLabel, aScript.url);
 
     scriptItem.setAttribute("tooltiptext", aScript.url);
--- a/browser/devtools/debugger/test/browser_dbg_createRemote.js
+++ b/browser/devtools/debugger/test/browser_dbg_createRemote.js
@@ -2,26 +2,32 @@
  * Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
 // Tests that a remote debugger can be created in a new window.
 
 var gWindow = null;
 var gTab = null;
+var gRemotePort = null;
 var gAutoConnect = null;
 
 const TEST_URL = EXAMPLE_URL + "browser_dbg_iframes.html";
 
 function test() {
   debug_remote(TEST_URL, function(aTab, aDebuggee, aWindow) {
     gTab = aTab;
     gWindow = aWindow;
     let gDebugger = gWindow.contentWindow;
 
+    info("Current remote port: " +
+      Services.prefs.getIntPref("devtools.debugger.remote-port"));
+    info("Current autoconnect flag: " +
+      Services.prefs.getBoolPref("devtools.debugger.remote-autoconnect"));
+
     is(gDebugger.document.getElementById("close").getAttribute("hidden"), "true",
       "The close button should be hidden in a remote debugger.");
 
     is(gDebugger.DebuggerController.activeThread.paused, false,
       "Should be running after debug_remote.");
 
     gDebugger.DebuggerController.activeThread.addOneTimeListener("framesadded", function() {
       Services.tm.currentThread.dispatch({ run: function() {
@@ -55,26 +61,51 @@ function test() {
   },
   function beforeTabAdded() {
     if (!DebuggerServer.initialized) {
       DebuggerServer.init(function() { return true; });
       DebuggerServer.addBrowserActors();
     }
     DebuggerServer.closeListener();
 
+    gRemotePort = Services.prefs.getIntPref("devtools.debugger.remote-port");
     gAutoConnect = Services.prefs.getBoolPref("devtools.debugger.remote-autoconnect");
-    Services.prefs.setBoolPref("devtools.debugger.remote-autoconnect", true);
 
     // Open the listener at some point in the future to test automatic reconnect.
-    window.setTimeout(function() {
-      DebuggerServer.openListener(
-        Services.prefs.getIntPref("devtools.debugger.remote-port"));
-    }, Math.random() * 1000);
+    openListener(gRemotePort + 1);
   });
 }
 
+let attempts = 0;
+
+function openListener(port) {
+  Services.prefs.setIntPref("devtools.debugger.remote-port", port);
+  Services.prefs.setBoolPref("devtools.debugger.remote-autoconnect", true);
+
+  info("Attempting to open a new listener on port " + port);
+  try {
+    info("Closing listener...");
+    DebuggerServer.closeListener();
+    info("Opening listener...");
+    DebuggerServer.openListener(port);
+  } catch (e) {
+    info(e);
+    info("Exception caught when opening listener on port " + port);
+    info("Retrying with port " + (++port));
+
+    if (++attempts < 100) {
+      DebuggerServer.closeListener();
+      openListener(port);
+    } else {
+      ok(false, "Timed out while opening a listener.");
+    }
+  }
+}
+
 registerCleanupFunction(function() {
+  Services.prefs.setIntPref("devtools.debugger.remote-port", gRemotePort);
   Services.prefs.setBoolPref("devtools.debugger.remote-autoconnect", gAutoConnect);
   removeTab(gTab);
   gWindow = null;
   gTab = null;
+  gRemotePort = null;
   gAutoConnect = null;
 });
--- a/browser/devtools/debugger/test/browser_dbg_propertyview-01.js
+++ b/browser/devtools/debugger/test/browser_dbg_propertyview-01.js
@@ -32,66 +32,101 @@ function testSimpleCall() {
 
 function testScriptLabelShortening() {
   gDebugger.DebuggerController.activeThread.resume(function() {
     let vs = gDebugger.DebuggerView.Scripts;
     let ss = gDebugger.DebuggerController.SourceScripts;
     vs.empty();
     vs._scripts.removeEventListener("select", vs._onScriptsChange, false);
 
-    is(ss._trimUrlQuery("a/b/c.d?test=1&random=4"), "a/b/c.d",
+    is(ss.trimUrlQuery("a/b/c.d?test=1&random=4#reference"), "a/b/c.d",
       "Trimming the url query isn't done properly.");
 
     let urls = [
-      { href: "ichi://some.address.com/random/", leaf: "subrandom/" },
-      { href: "ni://another.address.org/random/subrandom/", leaf: "page.html" },
-      { href: "san://interesting.address.gro/random/", leaf: "script.js" },
-      { href: "shi://interesting.address.moc/random/", leaf: "script.js" },
-      { href: "shi://interesting.address.moc/random/", leaf: "x/script.js" },
-      { href: "shi://interesting.address.moc/random/", leaf: "x/y/script.js?a=1" },
-      { href: "shi://interesting.address.moc/random/x/", leaf: "y/script.js?a=1&b=2", dupe: true },
-      { href: "shi://interesting.address.moc/random/x/y/", leaf: "script.js?a=1&b=2&c=3", dupe: true },
-      { href: "go://random/", leaf: "script_t1.js&a=1&b=2&c=3" },
-      { href: "roku://random/", leaf: "script_t2.js#id" },
-      { href: "nana://random/", leaf: "script_t3.js#id?a=1&b=2" }
+      { href: "http://some.address.com/random/", leaf: "subrandom/" },
+      { href: "http://some.address.com/random/", leaf: "suprandom/?a=1" },
+      { href: "http://some.address.com/random/", leaf: "?a=1" },
+      { href: "https://another.address.org/random/subrandom/", leaf: "page.html" },
+
+      { href: "ftp://interesting.address.org/random/", leaf: "script.js" },
+      { href: "ftp://interesting.address.com/random/", leaf: "script.js" },
+      { href: "ftp://interesting.address.com/random/", leaf: "x/script.js" },
+      { href: "ftp://interesting.address.com/random/", leaf: "x/y/script.js?a=1" },
+      { href: "ftp://interesting.address.com/random/x/", leaf: "y/script.js?a=1&b=2", dupe: true },
+      { href: "ftp://interesting.address.com/random/x/y/", leaf: "script.js?a=1&b=2&c=3", dupe: true },
+      { href: "ftp://interesting.address.com/random/", leaf: "x/y/script.js?a=2", dupe: true },
+      { href: "ftp://interesting.address.com/random/x/", leaf: "y/script.js?a=2&b=3", dupe: true },
+      { href: "ftp://interesting.address.com/random/x/y/", leaf: "script.js?a=2&b=3&c=4", dupe: true },
+
+      { href: "file://random/", leaf: "script_t1.js&a=1&b=2&c=3" },
+      { href: "file://random/", leaf: "script_t2_1.js#id" },
+      { href: "file://random/", leaf: "script_t2_2.js?a" },
+      { href: "file://random/", leaf: "script_t2_3.js&b" },
+      { href: "resource://random/", leaf: "script_t3_1.js#id?a=1&b=2" },
+      { href: "resource://random/", leaf: "script_t3_2.js?a=1&b=2#id" },
+      { href: "resource://random/", leaf: "script_t3_3.js&a=1&b=2#id" }
     ];
 
     urls.forEach(function(url) {
       executeSoon(function() {
         let loc = url.href + url.leaf;
         vs.addScript(ss._getScriptLabel(loc, url.href), { url: loc }, true);
       });
     });
 
     executeSoon(function() {
+      info("Script labels:");
+      info(vs.scriptLabels.toSource());
+
+      info("Script locations:");
+      info(vs.scriptLocations.toSource());
+
       urls.forEach(function(url) {
         let loc = url.href + url.leaf;
-        ok(url.dupe || vs.contains(loc), "Script url is incorrect: " + loc);
+        if (url.dupe) {
+          ok(!vs.contains(loc), "Shouldn't contain script: " + loc);
+        } else {
+          ok(vs.contains(loc), "Should contain script: " + loc);
+        }
       });
 
-      ok(gDebugger.DebuggerView.Scripts.containsLabel("subrandom/"),
+      ok(gDebugger.DebuggerView.Scripts.containsLabel("random/subrandom/"),
         "Script (0) label is incorrect.");
+      ok(gDebugger.DebuggerView.Scripts.containsLabel("random/suprandom/?a=1"),
+        "Script (1) label is incorrect.");
+      ok(gDebugger.DebuggerView.Scripts.containsLabel("random/?a=1"),
+        "Script (2) label is incorrect.");
       ok(gDebugger.DebuggerView.Scripts.containsLabel("page.html"),
-        "Script (1) label is incorrect.");
+        "Script (3) label is incorrect.");
+
       ok(gDebugger.DebuggerView.Scripts.containsLabel("script.js"),
-        "Script (2) label is incorrect.");
-      ok(gDebugger.DebuggerView.Scripts.containsLabel("shi://interesting.address.moc/random/script.js"),
-        "Script (3) label is incorrect.");
-      ok(gDebugger.DebuggerView.Scripts.containsLabel("x/script.js"),
         "Script (4) label is incorrect.");
-      ok(gDebugger.DebuggerView.Scripts.containsLabel("x/y/script.js"),
+      ok(gDebugger.DebuggerView.Scripts.containsLabel("random/script.js"),
         "Script (5) label is incorrect.");
-      ok(gDebugger.DebuggerView.Scripts.containsLabel("script_t1.js"),
+      ok(gDebugger.DebuggerView.Scripts.containsLabel("random/x/script.js"),
         "Script (6) label is incorrect.");
-      ok(gDebugger.DebuggerView.Scripts.containsLabel("script_t2.js"),
+      ok(gDebugger.DebuggerView.Scripts.containsLabel("script.js?a=1"),
         "Script (7) label is incorrect.");
-      ok(gDebugger.DebuggerView.Scripts.containsLabel("script_t3.js"),
+
+      ok(gDebugger.DebuggerView.Scripts.containsLabel("script_t1.js"),
         "Script (8) label is incorrect.");
+      ok(gDebugger.DebuggerView.Scripts.containsLabel("script_t2_1.js"),
+        "Script (9) label is incorrect.");
+      ok(gDebugger.DebuggerView.Scripts.containsLabel("script_t2_2.js"),
+        "Script (10) label is incorrect.");
+      ok(gDebugger.DebuggerView.Scripts.containsLabel("script_t2_3.js"),
+        "Script (11) label is incorrect.");
+      ok(gDebugger.DebuggerView.Scripts.containsLabel("script_t3_1.js"),
+        "Script (12) label is incorrect.");
+      ok(gDebugger.DebuggerView.Scripts.containsLabel("script_t3_2.js"),
+        "Script (13) label is incorrect.");
+      ok(gDebugger.DebuggerView.Scripts.containsLabel("script_t3_3.js"),
+        "Script (14) label is incorrect.");
 
-      is(vs._scripts.itemCount, 9,
+      is(vs._scripts.itemCount, urls.filter(function(url) !url.dupe).length,
         "Didn't get the correct number of scripts in the list.");
 
       closeDebuggerAndFinish();
     });
   });
 }
 
 registerCleanupFunction(function() {
--- a/browser/locales/en-US/chrome/browser/aboutSessionRestore.dtd
+++ b/browser/locales/en-US/chrome/browser/aboutSessionRestore.dtd
@@ -9,15 +9,15 @@
 <!ENTITY restorepage.errorTitle     "Well, this is embarrassing.">
 <!ENTITY restorepage.problemDesc    "&brandShortName; is having trouble recovering your windows and tabs. This is usually caused by a recently opened web page.">
 <!ENTITY restorepage.tryThis        "You can try:">
 <!ENTITY restorepage.restoreSome    "Removing one or more tabs that you think may be causing the problem">
 <!ENTITY restorepage.startNew       "Starting an entirely new browsing session">
 
 <!ENTITY restorepage.tryagainButton "Restore">
 <!ENTITY restorepage.restore.access "R">
-<!ENTITY restorepage.cancelButton   "Start New Session">
-<!ENTITY restorepage.cancel.access  "S">
+<!ENTITY restorepage.closeButton    "Close">
+<!ENTITY restorepage.close.access   "C">
 
 <!ENTITY restorepage.restoreHeader  "Restore">
 <!ENTITY restorepage.listHeader     "Windows and Tabs">
 <!-- LOCALIZATION NOTE: &#37;S will be replaced with a number. -->
 <!ENTITY restorepage.windowLabel    "Window &#37;S">
--- a/browser/themes/gnomestripe/devtools/debugger.css
+++ b/browser/themes/gnomestripe/devtools/debugger.css
@@ -11,23 +11,26 @@
 /**
  * Debugger content
  */
 
 #dbg-content {
   padding: 0;
 }
 
+#scripts {
+  max-width: 350px;
+}
+
 /**
  * Lists and headers
  */
 
 .list-item {
   padding: 2px;
-  font: -moz-list;
 }
 
 .list-item.selected {
   background: Highlight;
   color: HighlightText;
 }
 
 .list-item.empty {
@@ -43,16 +46,17 @@
 }
 
 .dbg-stackframe {
   -moz-padding-start: 4px;
   -moz-padding-end: 4px;
 }
 
 .dbg-stackframe-name {
+  -moz-padding-end: 4px;
   font-weight: 600;
 }
 
 /**
  * Properties view
  */
 
 #variables {
@@ -60,27 +64,25 @@
 }
 
 /**
  * Property element details container
  */
 
 .details {
   -moz-margin-start: 10px;
-  font: -moz-list;
 }
 
 /**
  * Scope element
  */
 
 .scope > .title {
   text-shadow: 0 1px #222;
   color: #fff;
-  font: -moz-list;
 }
 
 .scope > .title > .arrow {
   margin-top: -2px;
 }
 
 .scope > .title > .name {
   padding-top: 2px;
--- a/browser/themes/pinstripe/devtools/debugger.css
+++ b/browser/themes/pinstripe/devtools/debugger.css
@@ -13,23 +13,26 @@
 /**
  * Debugger content
  */
 
 #dbg-content {
   padding: 0;
 }
 
+#scripts {
+  max-width: 350px;
+}
+
 /**
  * Lists and headers
  */
 
 .list-item {
   padding: 2px;
-  font: -moz-list;
 }
 
 .list-item.selected {
   background: Highlight;
   color: HighlightText;
 }
 
 .list-item.empty {
@@ -45,16 +48,17 @@
 }
 
 .dbg-stackframe {
   -moz-padding-start: 4px;
   -moz-padding-end: 4px;
 }
 
 .dbg-stackframe-name {
+  -moz-padding-end: 4px;
   font-weight: 600;
 }
 
 /**
  * Properties view
  */
 
 #variables {
@@ -62,27 +66,25 @@
 }
 
 /**
  * Property element details container
  */
 
 .details {
   -moz-margin-start: 10px;
-  font: -moz-list;
 }
 
 /**
  * Scope element
  */
 
 .scope > .title {
   text-shadow: 0 1px #222;
   color: #fff;
-  font: -moz-list;
 }
 
 .scope > .title > .arrow {
   margin-top: -2px;
 }
 
 .scope > .title > .name {
   padding-top: 2px;
--- a/browser/themes/winstripe/devtools/debugger.css
+++ b/browser/themes/winstripe/devtools/debugger.css
@@ -11,23 +11,26 @@
 /**
  * Debugger content
  */
 
 #dbg-content {
   padding: 0;
 }
 
+#scripts {
+  max-width: 350px;
+}
+
 /**
  * Lists and headers
  */
 
 .list-item {
   padding: 2px;
-  font: -moz-list;
 }
 
 .list-item.selected {
   background: Highlight;
   color: HighlightText;
 }
 
 .list-item.empty {
@@ -43,16 +46,17 @@
 }
 
 .dbg-stackframe {
   -moz-padding-start: 4px;
   -moz-padding-end: 4px;
 }
 
 .dbg-stackframe-name {
+  -moz-padding-end: 4px;
   font-weight: 600;
 }
 
 /**
  * Properties view
  */
 
 #variables {
@@ -60,27 +64,25 @@
 }
 
 /**
  * Property element details container
  */
 
 .details {
   -moz-margin-start: 10px;
-  font: -moz-list;
 }
 
 /**
  * Scope element
  */
 
 .scope > .title {
   text-shadow: 0 1px #222;
   color: #fff;
-  font: -moz-list;
 }
 
 .scope > .title > .arrow {
   margin-top: -2px;
 }
 
 .scope > .title > .name {
   padding-top: 2px;