Merge central to inbound
authorMarco Bonardo <mbonardo@mozilla.com>
Fri, 02 Mar 2012 14:57:10 +0100
changeset 88151 f3ac2ec81d34e4cd9d870c43f15e3695cdd72d42
parent 88150 0c183373c89e1871b9f6289949504a42d5fbba92 (current diff)
parent 88139 343ec916dfd526957ecff6b224d00634be856dd9 (diff)
child 88152 f0cc27e3731c8ff2ce405652901a15eff240ad5f
push id22173
push userbmo@edmorley.co.uk
push dateSat, 03 Mar 2012 13:14:42 +0000
treeherdermozilla-central@ed57abebd328 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone13.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 central to inbound
browser/themes/gnomestripe/inspector.css
browser/themes/pinstripe/inspector.css
browser/themes/winstripe/inspector.css
--- a/browser/devtools/debugger/debugger-view.js
+++ b/browser/devtools/debugger/debugger-view.js
@@ -145,45 +145,45 @@ DebuggerView.Stackframes = {
 
   /**
    * Adds a frame to the stackframes container.
    * If the frame already exists (was previously added), null is returned.
    * Otherwise, the newly created element is returned.
    *
    * @param number aDepth
    *        The frame depth specified by the debugger.
-   * @param string aFrameIdText
-   *        The id to be displayed in the list.
    * @param string aFrameNameText
    *        The name to be displayed in the list.
+   * @param string aFrameDetailsText
+   *        The details to be displayed in the list.
    * @return object
    *         The newly created html node representing the added frame.
    */
-  addFrame: function DVF_addFrame(aDepth, aFrameIdText, aFrameNameText) {
+  addFrame: function DVF_addFrame(aDepth, aFrameNameText, aFrameDetailsText) {
     // make sure we don't duplicate anything
     if (document.getElementById("stackframe-" + aDepth)) {
       return null;
     }
 
     let frame = document.createElement("div");
-    let frameId = document.createElement("span");
     let frameName = document.createElement("span");
+    let frameDetails = document.createElement("span");
 
     // create a list item to be added to the stackframes container
     frame.id = "stackframe-" + aDepth;
     frame.className = "dbg-stackframe list-item";
 
-    // this list should display the id and name of the frame
-    frameId.className = "dbg-stackframe-id";
+    // this list should display the name and details for the frame
     frameName.className = "dbg-stackframe-name";
-    frameId.appendChild(document.createTextNode(aFrameIdText));
+    frameDetails.className = "dbg-stackframe-details";
     frameName.appendChild(document.createTextNode(aFrameNameText));
+    frameDetails.appendChild(document.createTextNode(aFrameDetailsText));
 
-    frame.appendChild(frameId);
     frame.appendChild(frameName);
+    frame.appendChild(frameDetails);
 
     this._frames.appendChild(frame);
 
     // return the element for later use if necessary
     return frame;
   },
 
   /**
@@ -1069,25 +1069,41 @@ DebuggerView.Scripts = {
   },
 
   /**
    * 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._scripts.getElementsByAttribute("value", aUrl).length > 0) {
       return true;
     }
     return false;
   },
 
   /**
+   * Checks whether the script with the specified label is among the scripts
+   * known to the debugger and shown in the list.
+   *
+   * @param string aLabel
+   *        The script label.
+   * @return boolean
+   */
+  containsLabel: function DVS_containsLabel(aLabel) {
+    if (this._scripts.getElementsByAttribute("label", aLabel).length > 0) {
+      return true;
+    }
+    return false;
+  },
+
+  /**
    * Checks whether the script with the specified URL is selected in the list.
    *
    * @param string aUrl
    *        The script URL.
    */
   isSelected: function DVS_isSelected(aUrl) {
     if (this._scripts.selectedItem &&
         this._scripts.selectedItem.value == aUrl) {
@@ -1104,40 +1120,40 @@ DebuggerView.Scripts = {
    */
    selectScript: function DVS_selectScript(aUrl) {
     for (let i = 0; i < this._scripts.itemCount; i++) {
       if (this._scripts.getItemAtIndex(i).value == aUrl) {
         this._scripts.selectedIndex = i;
         break;
       }
     }
-   },
+  },
 
   /**
    * Adds a script to the scripts container.
    * If the script already exists (was previously added), null is returned.
    * Otherwise, the newly created element is returned.
    *
-   * @param string aUrl
-   *        The script url.
+   * @param string aLabel
+   *        The simplified script location to be shown.
    * @param string aScript
    *        The source script.
-   * @param string aScriptNameText
-   *        Optional, title displayed instead of url.
    * @return object
    *         The newly created html node representing the added script.
    */
-  addScript: function DVS_addScript(aUrl, aSource, aScriptNameText) {
+  addScript: function DVS_addScript(aLabel, aScript) {
     // make sure we don't duplicate anything
-    if (this.contains(aUrl)) {
+    if (this.containsLabel(aLabel)) {
       return null;
     }
 
-    let script = this._scripts.appendItem(aScriptNameText || aUrl, aUrl);
-    script.setUserData("sourceScript", aSource, null);
+    let script = this._scripts.appendItem(aLabel, aScript.url);
+    script.setAttribute("tooltiptext", aScript.url);
+    script.setUserData("sourceScript", aScript, null);
+
     this._scripts.selectedItem = script;
     return script;
   },
 
   /**
    * Returns the list of URIs for scripts in the page.
    */
   scriptLocations: function DVS_scriptLocations() {
--- a/browser/devtools/debugger/debugger.css
+++ b/browser/devtools/debugger/debugger.css
@@ -62,16 +62,36 @@
 #stack {
   width: 200px;
 }
 
 #stackframes {
   overflow: auto;
 }
 
+.dbg-stackframe {
+  display: block;
+}
+
+.dbg-stackframe-name {
+  float: left;
+}
+
+.dbg-stackframe-details {
+  float: right;
+}
+
+.dbg-stackframe-name:-moz-locale-dir(rtl) {
+  float: right;
+}
+
+.dbg-stackframe-details:-moz-locale-dir(rtl) {
+  float: left;
+}
+
 /**
  * Properties elements
  */
 
 #properties {
   width: 250px;
 }
 
--- a/browser/devtools/debugger/debugger.js
+++ b/browser/devtools/debugger/debugger.js
@@ -365,20 +365,22 @@ var StackFrames = {
   /**
    * Adds the specified stack frame to the list.
    *
    * @param Debugger.Frame aFrame
    *        The new frame to add.
    */
   _addFramePanel: function SF_addFramePanel(aFrame) {
     let depth = aFrame.depth;
-    let idText = "#" + aFrame.depth + " ";
-    let nameText = this._frameTitle(aFrame);
+    let label = SourceScripts._getScriptLabel(aFrame.where.url);
 
-    let panel = DebuggerView.Stackframes.addFrame(depth, idText, nameText);
+    let startText = this._frameTitle(aFrame);
+    let endText = label + ":" + aFrame.where.line;
+
+    let panel = DebuggerView.Stackframes.addFrame(depth, startText, endText);
 
     if (panel) {
       panel.stackFrame = aFrame;
     }
   },
 
   /**
    * Loads more stack frames from the debugger server cache.
@@ -392,17 +394,17 @@ var StackFrames = {
    * Create a textual representation for the stack frame specified, for
    * displaying in the stack frame list.
    *
    * @param Debugger.Frame aFrame
    *        The stack frame to label.
    */
   _frameTitle: function SF_frameTitle(aFrame) {
     if (aFrame.type == "call") {
-      return aFrame["calleeName"] ? aFrame["calleeName"] + "()" : "(anonymous)";
+      return aFrame["calleeName"] ? aFrame["calleeName"] : "(anonymous)";
     }
 
     return "(" + aFrame.type + ")";
   }
 };
 
 StackFrames.onPaused = StackFrames.onPaused.bind(StackFrames);
 StackFrames.onFrames = StackFrames.onFrames.bind(StackFrames);
@@ -411,31 +413,33 @@ StackFrames.onClick = StackFrames.onClic
 
 /**
  * Keeps the source script list up-to-date, using the thread client's
  * source script cache.
  */
 var SourceScripts = {
   pageSize: 25,
   activeThread: null,
+  _labelsCache: null,
 
   /**
    * Watch a given thread client.
    * @param object aThreadClient
    *        The thread client.
    * @param function aCallback
    *        The next function in the initialization sequence.
    */
   connect: function SS_connect(aThreadClient, aCallback) {
     DebuggerView.Scripts.addChangeListener(this.onChange);
 
     this.activeThread = aThreadClient;
     aThreadClient.addListener("paused", this.onPaused);
     aThreadClient.addListener("scriptsadded", this.onScripts);
     aThreadClient.addListener("scriptscleared", this.onScriptsCleared);
+    this.clearLabelsCache();
     this.onScriptsCleared();
     aCallback && aCallback();
   },
 
   /**
    * Disconnect from the client.
    */
   disconnect: function TS_disconnect() {
@@ -504,36 +508,96 @@ var SourceScripts = {
       if (/javascript/.test(aContentType)) {
         window.editor.setMode(SourceEditor.MODES.JAVASCRIPT);
       } else {
         window.editor.setMode(SourceEditor.MODES.HTML);
       }
       return;
     }
 
-    let url = aUrl;
-    // Trim the query part.
-    let q = url.indexOf('?');
-    if (q > -1) {
-      url = url.slice(0, q);
-    }
-
-    if (url.slice(-3) == ".js") {
+    if (this._trimUrlQuery(aUrl).slice(-3) == ".js") {
       window.editor.setMode(SourceEditor.MODES.JAVASCRIPT);
     } else {
       window.editor.setMode(SourceEditor.MODES.HTML);
     }
   },
 
   /**
+   * Trims the query part of a url string, if necessary.
+   *
+   * @param string aUrl
+   *        The script url.
+   * @return string
+   */
+  _trimUrlQuery: function SS_trimUrlQuery(aUrl) {
+    let q = aUrl.indexOf('?');
+    if (q > -1) {
+      return aUrl.slice(0, q);
+    }
+    return aUrl;
+  },
+
+  /**
+   * 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
+   *        defalult to debugged panrent window location.
+   * @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 href = aHref || window.parent.content.location.href;
+    let pathElements = url.split("/");
+    let label = pathElements.pop() || (pathElements.pop() + "/");
+
+    // if the label as a leaf name is alreay 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;
+  },
+
+  /**
+   * Clears the labels cache, populated by SS_getScriptLabel().
+   * This should be done every time the content location changes.
+   */
+  clearLabelsCache: function SS_clearLabelsCache() {
+    this._labelsCache = {};
+  },
+
+  /**
    * Add the specified script to the list and display it in the editor if the
    * editor is empty.
    */
   _addScript: function SS_addScript(aScript) {
-    DebuggerView.Scripts.addScript(aScript.url, aScript);
+    DebuggerView.Scripts.addScript(this._getScriptLabel(aScript.url), aScript);
 
     if (window.editor.getCharCount() == 0) {
       this._showScript(aScript);
     }
   },
 
   /**
    * Load the editor with the script text if available, otherwise fire an event
--- a/browser/devtools/debugger/test/browser_dbg_clean-exit.js
+++ b/browser/devtools/debugger/test/browser_dbg_clean-exit.js
@@ -5,19 +5,17 @@
 
 // Test that closing a tab with the debugger in a paused state exits cleanly.
 
 var gPane = null;
 var gTab = null;
 var gDebuggee = null;
 var gDebugger = null;
 
-const DEBUGGER_TAB_URL = "http://example.com/browser/browser/devtools/" +
-                         "debugger/test/" +
-                         "browser_dbg_debuggerstatement.html";
+const DEBUGGER_TAB_URL = EXAMPLE_URL + "browser_dbg_debuggerstatement.html";
 
 function test() {
   debug_tab_pane(DEBUGGER_TAB_URL, function(aTab, aDebuggee, aPane) {
     gTab = aTab;
     gDebuggee = aDebuggee;
     gPane = aPane;
     gDebugger = gPane.debuggerWindow;
 
--- a/browser/devtools/debugger/test/browser_dbg_debuggerstatement.js
+++ b/browser/devtools/debugger/test/browser_dbg_debuggerstatement.js
@@ -3,19 +3,17 @@
  * Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
 // Tests the behavior of the debugger statement.
 
 var gClient = null;
 var gTab = null;
-const DEBUGGER_TAB_URL = "http://example.com/browser/browser/devtools/" +
-                         "debugger/test/" +
-                         "browser_dbg_debuggerstatement.html";
+const DEBUGGER_TAB_URL = EXAMPLE_URL + "browser_dbg_debuggerstatement.html";
 
 function test()
 {
   let transport = DebuggerServer.connectPipe();
   gClient = new DebuggerClient(transport);
   gClient.connect(function(aType, aTraits) {
     gTab = addTab(DEBUGGER_TAB_URL, function() {
       attach_tab_actor_for_url(gClient, DEBUGGER_TAB_URL, function(actor, response) {
--- a/browser/devtools/debugger/test/browser_dbg_propertyview-01.js
+++ b/browser/devtools/debugger/test/browser_dbg_propertyview-01.js
@@ -78,12 +78,65 @@ function testSimpleCall() {
     }}, 0);
   });
 
   gDebuggee.simpleCall();
 }
 
 function resumeAndFinish() {
   gDebugger.StackFrames.activeThread.resume(function() {
-    removeTab(gTab);
-    finish();
+    let vs = gDebugger.DebuggerView.Scripts;
+    let ss = gDebugger.SourceScripts;
+
+    is(ss._trimUrlQuery("a/b/c.d?test=1&random=4"), "a/b/c.d",
+      "Trimming the url query isn't done properly.");
+
+    let urls = [
+      { href: "ici://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: "si://interesting.address.moc/random/", leaf: "script.js" },
+      { href: "si://interesting.address.moc/random/", leaf: "x/script.js" },
+      { href: "si://interesting.address.moc/random/", leaf: "x/y/script.js?a=1" },
+      { href: "si://interesting.address.moc/random/x/", leaf: "y/script.js?a=1&b=2" },
+      { href: "si://interesting.address.moc/random/x/y/", leaf: "script.js?a=1&b=2&c=3" }
+    ];
+
+    vs._scripts.removeEventListener("select", vs._onScriptsChange, false);
+
+    urls.forEach(function(url) {
+      executeSoon(function() {
+        let loc = url.href + url.leaf;
+        vs.addScript(ss._getScriptLabel(loc, url.href), { url: loc });
+      });
+    });
+
+    executeSoon(function() {
+      for (let i = 0; i < vs._scripts.itemCount; i++) {
+        let lab = vs._scripts.getItemAtIndex(i).getAttribute("label");
+        let loc = urls[i].href + urls[i].leaf;
+
+        info("label: " + i + " " + lab);
+        ok(vs.contains(loc), "Script url is incorrect: " + loc);
+      }
+
+      ok(gDebugger.DebuggerView.Scripts.containsLabel("subrandom/"),
+        "Script (0) label is incorrect.");
+      ok(gDebugger.DebuggerView.Scripts.containsLabel("page.html"),
+        "Script (1) label is incorrect.");
+      ok(gDebugger.DebuggerView.Scripts.containsLabel("script.js"),
+        "Script (2) label is incorrect.");
+      ok(gDebugger.DebuggerView.Scripts.containsLabel("si://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"),
+        "Script (5) label is incorrect.");
+
+      is(vs._scripts.itemCount, 6,
+        "Got too many script items in the list!");
+
+
+      removeTab(gTab);
+      finish();
+    });
   });
 }
--- a/browser/devtools/debugger/test/browser_dbg_propertyview-07.js
+++ b/browser/devtools/debugger/test/browser_dbg_propertyview-07.js
@@ -1,18 +1,17 @@
 /* vim:set ts=2 sw=2 sts=2 et: */
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 /**
  * Make sure that the property view displays function parameters.
  */
 
-const TAB_URL = "http://example.com/browser/browser/devtools/debugger/test/" +
-                "browser_dbg_frame-parameters.html";
+const TAB_URL = EXAMPLE_URL + "browser_dbg_frame-parameters.html";
 
 var gPane = null;
 var gTab = null;
 var gDebuggee = null;
 var gDebugger = null;
 
 function test()
 {
--- a/browser/devtools/debugger/test/browser_dbg_propertyview-08.js
+++ b/browser/devtools/debugger/test/browser_dbg_propertyview-08.js
@@ -1,18 +1,17 @@
 /* vim:set ts=2 sw=2 sts=2 et: */
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 /**
  * Make sure that the property view displays the properties of objects.
  */
 
-const TAB_URL = "http://example.com/browser/browser/devtools/debugger/test/" +
-                "browser_dbg_frame-parameters.html";
+const TAB_URL = EXAMPLE_URL + "browser_dbg_frame-parameters.html";
 
 var gPane = null;
 var gTab = null;
 var gDebuggee = null;
 var gDebugger = null;
 
 function test()
 {
--- a/browser/devtools/debugger/test/browser_dbg_script-switching.js
+++ b/browser/devtools/debugger/test/browser_dbg_script-switching.js
@@ -1,18 +1,18 @@
 /* vim:set ts=2 sw=2 sts=2 et: */
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 /**
  * Make sure that switching the displayed script in the UI works as advertised.
  */
 
-const TAB_URL = "http://example.com/browser/browser/devtools/debugger/" +
-                "test/browser_dbg_script-switching.html";
+const TAB_URL = EXAMPLE_URL + "browser_dbg_script-switching.html";
+
 let tempScope = {};
 Cu.import("resource:///modules/source-editor.jsm", tempScope);
 let SourceEditor = tempScope.SourceEditor;
 
 var gPane = null;
 var gTab = null;
 var gDebuggee = null;
 var gDebugger = null;
@@ -35,16 +35,34 @@ function testScriptsDisplay() {
     Services.tm.currentThread.dispatch({ run: function() {
       gScripts = gDebugger.DebuggerView.Scripts._scripts;
 
       is(gDebugger.StackFrames.activeThread.state, "paused",
         "Should only be getting stack frames while paused.");
 
       is(gScripts.itemCount, 2, "Found the expected number of scripts.");
 
+      for (let i = 0; i < gScripts.itemCount; i++) {
+        info("label: " + i + " " + gScripts.getItemAtIndex(i).getAttribute("label"));
+      }
+
+      let label1 = "test-script-switching-01.js";
+      let label2 = "test-script-switching-02.js";
+
+      ok(gDebugger.DebuggerView.Scripts.contains(EXAMPLE_URL +
+        label1), "First script url is incorrect.");
+      ok(gDebugger.DebuggerView.Scripts.contains(EXAMPLE_URL +
+        label2), "Second script url is incorrect.");
+
+      ok(gDebugger.DebuggerView.Scripts.containsLabel(
+        label1), "First script label is incorrect.");
+      ok(gDebugger.DebuggerView.Scripts.containsLabel(
+        label2), "Second script label is incorrect.");
+
+
       ok(gDebugger.editor.getText().search(/debugger/) != -1,
         "The correct script was loaded initially.");
 
       gDebugger.editor.addEventListener(SourceEditor.EVENTS.TEXT_CHANGED,
                                         function onChange() {
         gDebugger.editor.removeEventListener(SourceEditor.EVENTS.TEXT_CHANGED,
                                              onChange);
         testSwitchPaused();
--- a/browser/devtools/debugger/test/browser_dbg_select-line.js
+++ b/browser/devtools/debugger/test/browser_dbg_select-line.js
@@ -1,18 +1,18 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 /**
  * Make sure that selecting a stack frame loads the right script in the editor
  * pane and highlights the proper line.
  */
 
-const TAB_URL = "http://example.com/browser/browser/devtools/debugger/" +
-                "test/browser_dbg_script-switching.html";
+const TAB_URL = EXAMPLE_URL + "browser_dbg_script-switching.html";
+
 let tempScope = {};
 Cu.import("resource:///modules/source-editor.jsm", tempScope);
 let SourceEditor = tempScope.SourceEditor;
 
 var gPane = null;
 var gTab = null;
 var gDebuggee = null;
 var gDebugger = null;
--- a/browser/devtools/debugger/test/browser_dbg_update-editor-mode.js
+++ b/browser/devtools/debugger/test/browser_dbg_update-editor-mode.js
@@ -1,18 +1,18 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 /**
  * Make sure that updating the editor mode sets the right highlighting engine,
  * and script URIs with extra query parameters also get the right engine.
  */
 
-const TAB_URL = "http://example.com/browser/browser/devtools/debugger/" +
-                "test/browser_dbg_update-editor-mode.html";
+const TAB_URL = EXAMPLE_URL + "browser_dbg_update-editor-mode.html";
+
 let tempScope = {};
 Cu.import("resource:///modules/source-editor.jsm", tempScope);
 let SourceEditor = tempScope.SourceEditor;
 
 var gPane = null;
 var gTab = null;
 var gDebuggee = null;
 var gDebugger = null;
--- a/browser/devtools/debugger/test/head.js
+++ b/browser/devtools/debugger/test/head.js
@@ -9,21 +9,21 @@ let tempScope = {};
 Cu.import("resource:///modules/devtools/dbg-server.jsm", tempScope);
 Cu.import("resource:///modules/devtools/dbg-client.jsm", tempScope);
 Cu.import("resource:///modules/Services.jsm", tempScope);
 let DebuggerServer = tempScope.DebuggerServer;
 let DebuggerTransport = tempScope.DebuggerTransport;
 let DebuggerClient = tempScope.DebuggerClient;
 let Services = tempScope.Services;
 
-const TAB1_URL = "http://example.com/browser/browser/devtools/debugger/test/browser_dbg_tab1.html";
+const EXAMPLE_URL = "http://example.com/browser/browser/devtools/debugger/test/";
 
-const TAB2_URL = "http://example.com/browser/browser/devtools/debugger/test/browser_dbg_tab2.html";
-
-const STACK_URL = "http://example.com/browser/browser/devtools/debugger/test/browser_dbg_stack.html";
+const TAB1_URL = EXAMPLE_URL + "browser_dbg_tab1.html";
+const TAB2_URL = EXAMPLE_URL + "browser_dbg_tab2.html";
+const STACK_URL = EXAMPLE_URL + "browser_dbg_stack.html";
 
 if (!DebuggerServer.initialized) {
   DebuggerServer.init();
   DebuggerServer.addBrowserActors();
 }
 
 waitForExplicitFinish();
 
--- a/browser/devtools/highlighter/inspector.html
+++ b/browser/devtools/highlighter/inspector.html
@@ -1,14 +1,14 @@
 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
   "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
 
 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
 <head>
   <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
-  <link rel="stylesheet" href="chrome://browser/skin/inspector.css" type="text/css"/>
+  <link rel="stylesheet" href="chrome://browser/skin/devtools/htmlpanel.css" type="text/css"/>
 </head>
 <body role="application">
   <div id="attribute-editor">
     <input id="attribute-editor-input" />
   </div>
 </body>
 </html>
--- a/browser/devtools/highlighter/inspector.jsm
+++ b/browser/devtools/highlighter/inspector.jsm
@@ -865,17 +865,18 @@ InspectorUI.prototype = {
    * Delete the selected node. Called via the Inspector:DeleteNode command.
    */
   deleteNode: function IUI_deleteNode()
   {
     let selection = this.selection;
     let parent = this.selection.parentNode;
 
     // remove the node from the treepanel
-    this.treePanel.deleteChildBox(selection);
+    if (this.treePanel.isOpen())
+      this.treePanel.deleteChildBox(selection);
 
     // remove the node from content
     parent.removeChild(selection);
     this.breadcrumbs.invalidateHierarchy();
 
     // select the parent node in the highlighter, treepanel, breadcrumbs
     this.inspectNode(parent);
   },
@@ -1229,16 +1230,17 @@ InspectorUI.prototype = {
     btn.setAttribute("type", "radio");
     btn.setAttribute("group", "sidebar-tools");
     this.sidebarToolbar.appendChild(btn);
 
     // create tool iframe
     let iframe = this.chromeDoc.createElement("iframe");
     iframe.id = "devtools-sidebar-iframe-" + aRegObj.id;
     iframe.setAttribute("flex", "1");
+    iframe.setAttribute("tooltip", "aHTMLTooltip");
     this.sidebarDeck.appendChild(iframe);
 
     // wire up button to show the iframe
     this.bindToolEvent(btn, "click", function showIframe() {
       this.toolShow(aRegObj);
     }.bind(this));
   },
 
--- a/browser/devtools/styleinspector/CssLogic.jsm
+++ b/browser/devtools/styleinspector/CssLogic.jsm
@@ -72,20 +72,28 @@
  * - why their expectations may not have been fulfilled
  * - how browsers process CSS
  * @constructor
  */
 const Cc = Components.classes;
 const Ci = Components.interfaces;
 const Cu = Components.utils;
 
+const RX_UNIVERSAL_SELECTOR = /\s*\*\s*/g;
+const RX_NOT = /:not\((.*?)\)/g;
+const RX_PSEUDO_CLASS_OR_ELT = /(:[\w-]+\().*?\)/g;
+const RX_CONNECTORS = /\s*[\s>+~]\s*/g;
+const RX_ID = /\s*#\w+\s*/g;
+const RX_CLASS_OR_ATTRIBUTE = /\s*(?:\.\w+|\[.+?\])\s*/g;
+const RX_PSEUDO = /\s*:?:([\w-]+)(\(?\)?)\s*/g;
+
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 
-var EXPORTED_SYMBOLS = ["CssLogic"];
+var EXPORTED_SYMBOLS = ["CssLogic", "CssSelector"];
 
 function CssLogic()
 {
   // The cache of examined CSS properties.
   _propertyInfos: {};
 }
 
 /**
@@ -1427,61 +1435,107 @@ CssSelector.prototype = {
    * stylesheet.
    */
   get ruleLine()
   {
     return this._cssRule.line;
   },
 
   /**
+   * Retrieve the pseudo-elements that we support. This list should match the
+   * elements specified in layout/style/nsCSSPseudoElementList.h
+   */
+  get pseudoElements()
+  {
+    if (!CssSelector._pseudoElements) {
+      let pseudos = CssSelector._pseudoElements = new Set();
+      pseudos.add("after");
+      pseudos.add("before");
+      pseudos.add("first-letter");
+      pseudos.add("first-line");
+      pseudos.add("selection");
+      pseudos.add("-moz-focus-inner");
+      pseudos.add("-moz-focus-outer");
+      pseudos.add("-moz-list-bullet");
+      pseudos.add("-moz-list-number");
+      pseudos.add("-moz-math-anonymous");
+      pseudos.add("-moz-math-stretchy");
+      pseudos.add("-moz-progress-bar");
+      pseudos.add("-moz-selection");
+    }
+    return CssSelector._pseudoElements;
+  },
+
+  /**
    * Retrieve specificity information for the current selector.
    *
    * @see http://www.w3.org/TR/css3-selectors/#specificity
    * @see http://www.w3.org/TR/CSS2/selector.html
    *
    * @return {object} an object holding specificity information for the current
    * selector.
    */
   get specificity()
   {
     if (this._specificity) {
       return this._specificity;
     }
 
-    let specificity = {};
+    let specificity = {
+      ids: 0,
+      classes: 0,
+      tags: 0
+    };
 
-    specificity.ids = 0;
-    specificity.classes = 0;
-    specificity.tags = 0;
+    let text = this.text;
 
-    // Split on CSS combinators (section 5.2).
-    // TODO: We need to properly parse the selector. See bug 592743.
     if (!this.elementStyle) {
-      this.text.split(/[ >+]/).forEach(function(aSimple) {
-        // The regex leaves empty nodes combinators like ' > '
-        if (!aSimple) {
-          return;
-        }
-        // See http://www.w3.org/TR/css3-selectors/#specificity
-        // We can count the IDs by counting the '#' marks.
-        specificity.ids += (aSimple.match(/#/g) || []).length;
-        // Similar with class names and attribute matchers
-        specificity.classes += (aSimple.match(/\./g) || []).length;
-        specificity.classes += (aSimple.match(/\[/g) || []).length;
-        // Pseudo elements count as elements.
-        specificity.tags += (aSimple.match(/:/g) || []).length;
-        // If we have anything of substance before we get into ids/classes/etc
-        // then it must be a tag if it isn't '*'.
-        let tag = aSimple.split(/[#.[:]/)[0];
-        if (tag && tag != "*") {
+      // Remove universal selectors as they are not relevant as far as specificity
+      // is concerned.
+      text = text.replace(RX_UNIVERSAL_SELECTOR, "");
+
+      // not() is ignored but any selectors contained by it are counted. Let's
+      // remove the not() and keep the contents.
+      text = text.replace(RX_NOT, " $1");
+
+      // Simplify remaining psuedo classes & elements.
+      text = text.replace(RX_PSEUDO_CLASS_OR_ELT, " $1)");
+
+      // Replace connectors with spaces
+      text = text.replace(RX_CONNECTORS, " ");
+
+      text.split(/\s/).forEach(function(aSimple) {
+        // Count IDs.
+        aSimple = aSimple.replace(RX_ID, function() {
+          specificity.ids++;
+          return "";
+        });
+
+        // Count class names and attribute matchers.
+        aSimple = aSimple.replace(RX_CLASS_OR_ATTRIBUTE, function() {
+          specificity.classes++;
+          return "";
+        });
+
+        aSimple = aSimple.replace(RX_PSEUDO, function(aDummy, aPseudoName) {
+          if (this.pseudoElements.has(aPseudoName)) {
+            // Pseudo elements count as tags.
+            specificity.tags++;
+          } else {
+            // Pseudo classes count as classes.
+            specificity.classes++;
+          }
+          return "";
+        }.bind(this));
+
+        if (aSimple) {
           specificity.tags++;
         }
       }, this);
     }
-
     this._specificity = specificity;
 
     return this._specificity;
   },
 
   toString: function CssSelector_toString()
   {
     return this.text;
--- a/browser/devtools/styleinspector/CssRuleView.jsm
+++ b/browser/devtools/styleinspector/CssRuleView.jsm
@@ -98,16 +98,23 @@ var EXPORTED_SYMBOLS = ["CssRuleView",
  *        set of disabled properties.
  *
  * @constructor
  */
 function ElementStyle(aElement, aStore)
 {
   this.element = aElement;
   this.store = aStore || {};
+
+  // We don't want to overwrite this.store.userProperties so we only create it
+  // if it doesn't already exist.
+  if (!("userProperties" in this.store)) {
+    this.store.userProperties = new UserProperties();
+  }
+
   if (this.store.disabled) {
     this.store.disabled = aStore.disabled;
   } else {
     this.store.disabled = WeakMap();
   }
 
   let doc = aElement.ownerDocument;
 
@@ -417,31 +424,33 @@ Rule.prototype = {
   /**
    * Reapply all the properties in this rule, and update their
    * computed styles.  Store disabled properties in the element
    * style's store.  Will re-mark overridden properties.
    */
   applyProperties: function Rule_applyProperties()
   {
     let disabledProps = [];
+    let store = this.elementStyle.store;
 
     for each (let prop in this.textProps) {
       if (!prop.enabled) {
         disabledProps.push({
           name: prop.name,
           value: prop.value,
           priority: prop.priority
         });
         continue;
       }
 
+      store.userProperties.setProperty(this.style, prop.name, prop.value);
+
       this.style.setProperty(prop.name, prop.value, prop.priority);
-      // Refresh the property's value from the style, to reflect
+      // Refresh the property's priority from the style, to reflect
       // any changes made during parsing.
-      prop.value = this.style.getPropertyValue(prop.name);
       prop.priority = this.style.getPropertyPriority(prop.name);
       prop.updateComputed();
     }
     this.elementStyle._changed();
 
     // Store disabled properties in the disabled store.
     let disabled = this.elementStyle.store.disabled;
     disabled.set(this.style, disabledProps);
@@ -514,41 +523,42 @@ Rule.prototype = {
 
   /**
    * Get the list of TextProperties from the style.  Needs
    * to parse the style's cssText.
    */
   _getTextProperties: function Rule_getTextProperties()
   {
     this.textProps = [];
+    let store = this.elementStyle.store;
     let lines = this.style.cssText.match(CSS_LINE_RE);
     for each (let line in lines) {
       let matches = CSS_PROP_RE.exec(line);
       if(!matches || !matches[2])
         continue;
 
       let name = matches[1];
       if (this.inherited &&
           !this.elementStyle.domUtils.isInheritedProperty(name)) {
         continue;
       }
-
-      let prop = new TextProperty(this, name, matches[2], matches[3] || "");
+      let value = store.userProperties.getProperty(this.style, name, matches[2]);
+      let prop = new TextProperty(this, name, value, matches[3] || "");
       this.textProps.push(prop);
     }
 
     // Include properties from the disabled property store, if any.
     let disabledProps = this.elementStyle.store.disabled.get(this.style);
     if (!disabledProps) {
       return;
     }
 
     for each (let prop in disabledProps) {
-      let textProp = new TextProperty(this, prop.name,
-                                      prop.value, prop.priority);
+      let value = store.userProperties.getProperty(this.style, prop.name, prop.value);
+      let textProp = new TextProperty(this, prop.name, value, prop.priority);
       textProp.enabled = false;
       this.textProps.push(textProp);
     }
   },
 };
 
 /**
  * A single property in a rule's cssText.
@@ -988,16 +998,22 @@ TextPropertyEditor.prototype = {
     // Save the initial value as the last committed value,
     // for restoring after pressing escape.
     this.committed = { name: this.prop.name,
                        value: this.prop.value,
                        priority: this.prop.priority };
 
     appendText(this.element, ";");
 
+    this.warning = createChild(this.element, "div", {
+      hidden: "",
+      class: "ruleview-warning",
+      title: CssLogic.l10n("rule.warning.title"),
+    });
+
     // Holds the viewers for the computed properties.
     // will be populated in |_updateComputed|.
     this.computed = createChild(this.element, "ul", {
       class: "ruleview-computedlist",
     });
   },
 
   /**
@@ -1023,16 +1039,17 @@ TextPropertyEditor.prototype = {
 
     // Combine the property's value and priority into one string for
     // the value.
     let val = this.prop.value;
     if (this.prop.priority) {
       val += " !" + this.prop.priority;
     }
     this.valueSpan.textContent = val;
+    this.warning.hidden = this._validate();
 
     // Populate the computed styles.
     this._updateComputed();
   },
 
   _onStartEditing: function TextPropertyEditor_onStartEditing()
   {
     this.element.classList.remove("ruleview-overridden");
@@ -1158,16 +1175,33 @@ TextPropertyEditor.prototype = {
       let val = this._parseValue(aValue);
       this.prop.setValue(val.value, val.priority);
       this.committed.value = this.prop.value;
       this.committed.priority = this.prop.priority;
     } else {
       this.prop.setValue(this.committed.value, this.committed.priority);
     }
   },
+
+  /**
+   * Validate this property.
+   *
+   * @returns {Boolean}
+   *          True if the property value is valid, false otherwise.
+   */
+  _validate: function TextPropertyEditor_validate()
+  {
+    let name = this.prop.name;
+    let value = this.prop.value;
+    let style = this.doc.createElementNS(HTML_NS, "div").style;
+
+    style.setProperty(name, value, null);
+
+    return !!style.getPropertyValue(name);
+  },
 };
 
 /**
  * Mark a span editable.  |editableField| will listen for the span to
  * be focused and create an InlineEditor to handle text input.
  * Changes will be committed when the InlineEditor's input is blurred
  * or dropped when the user presses escape.
  *
@@ -1377,16 +1411,71 @@ InplaceEditor.prototype = {
     // Call the user's change handler if available.
     if (this.change) {
       this.change(this.input.value.trim());
     }
   }
 };
 
 /**
+ * Store of CSSStyleDeclarations mapped to properties that have been changed by
+ * the user.
+ */
+function UserProperties()
+{
+  this.weakMap = new WeakMap();
+}
+
+UserProperties.prototype = {
+  /**
+   * Get a named property for a given CSSStyleDeclaration.
+   *
+   * @param {CSSStyleDeclaration} aStyle
+   *        The CSSStyleDeclaration against which the property is mapped.
+   * @param {String} aName
+   *        The name of the property to get.
+   * @param {Boolean} aDefault
+   *        Indicates whether the property value is one entered by a user.
+   * @returns {String}
+   *          The property value if it has previously been set by the user, null
+   *          otherwise.
+   */
+  getProperty: function UP_getProperty(aStyle, aName, aDefault) {
+    let entry = this.weakMap.get(aStyle, null);
+
+    if (entry && aName in entry) {
+      return entry[aName];
+    }
+    return typeof aDefault != "undefined" ? aDefault : null;
+
+  },
+
+  /**
+   * Set a named property for a given CSSStyleDeclaration.
+   *
+   * @param {CSSStyleDeclaration} aStyle
+   *        The CSSStyleDeclaration against which the property is to be mapped.
+   * @param {String} aName
+   *        The name of the property to set.
+   * @param {String} aValue
+   *        The value of the property to set.
+   */
+  setProperty: function UP_setProperty(aStyle, aName, aValue) {
+    let entry = this.weakMap.get(aStyle, null);
+    if (entry) {
+      entry[aName] = aValue;
+    } else {
+      let props = {};
+      props[aName] = aValue;
+      this.weakMap.set(aStyle, props);
+    }
+  },
+};
+
+/**
  * Helper functions
  */
 
 /**
  * Create a child element with a set of attributes.
  *
  * @param {Element} aParent
  *        The parent node.
--- a/browser/devtools/styleinspector/StyleInspector.jsm
+++ b/browser/devtools/styleinspector/StyleInspector.jsm
@@ -77,17 +77,17 @@ StyleInspector.prototype = {
     // Were we invoked from the Highlighter?
     if (this.IUI) {
       this.openDocked = true;
       let isOpen = this.isOpen.bind(this);
 
       this.registrationObject = {
         id: "styleinspector",
         label: this.l10n("style.highlighter.button.label2"),
-        tooltiptext: this.l10n("style.highlighter.button.tooltip"),
+        tooltiptext: this.l10n("style.highlighter.button.tooltip2"),
         accesskey: this.l10n("style.highlighter.accesskey2"),
         context: this,
         get isOpen() isOpen(),
         onSelect: this.selectNode,
         onChanged: this.updateNode,
         show: this.open,
         hide: this.close,
         dim: this.dimTool,
--- a/browser/devtools/styleinspector/test/Makefile.in
+++ b/browser/devtools/styleinspector/test/Makefile.in
@@ -50,21 +50,23 @@ include $(topsrcdir)/config/rules.mk
   browser_bug683672.js \
   browser_styleinspector_bug_672746_default_styles.js \
   browser_styleinspector_bug_672744_search_filter.js \
   browser_bug589375_keybindings.js \
   browser_styleinspector_bug_689759_no_results_placeholder.js \
   browser_bug_692400_element_style.js \
   browser_csslogic_inherited.js \
   browser_ruleview_editor.js \
+  browser_ruleview_editor_changedvalues.js \
   browser_ruleview_inherit.js \
   browser_ruleview_manipulation.js \
   browser_ruleview_override.js \
   browser_ruleview_ui.js \
   browser_bug705707_is_content_stylesheet.js \
+  browser_bug_592743_specificity.js \
   head.js \
   $(NULL)
 
 _BROWSER_TEST_PAGES = \
   browser_bug683672.html \
   browser_bug705707_is_content_stylesheet.html \
   browser_bug705707_is_content_stylesheet_imported.css \
   browser_bug705707_is_content_stylesheet_imported2.css \
new file mode 100644
--- /dev/null
+++ b/browser/devtools/styleinspector/test/browser_bug_592743_specificity.js
@@ -0,0 +1,49 @@
+/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Tests that CSS specificity is properly calculated.
+
+let tempScope = {};
+Cu.import("resource:///modules/devtools/CssLogic.jsm", tempScope);
+let CssLogic = tempScope.CssLogic;
+let CssSelector = tempScope.CssSelector;
+
+function test()
+{
+  let tests = [
+    {text: "*", expected: "000"},
+    {text: "LI", expected: "001"},
+    {text: "UL LI", expected: "002"},
+    {text: "UL OL+LI", expected: "003"},
+    {text: "H1 + *[REL=up]", expected: "011"},
+    {text: "UL OL LI.red", expected: "013"},
+    {text: "LI.red.level", expected: "021"},
+    {text: ".red .level", expected: "020"},
+    {text: "#x34y", expected: "100"},
+    {text: "#s12:not(FOO)", expected: "101"},
+    {text: "body#home div#warning p.message", expected: "213"},
+    {text: "* body#home div#warning p.message", expected: "213"},
+    {text: "#footer *:not(nav) li", expected: "102"},
+    {text: "bar:nth-child(1n+0)", expected: "011"},
+    {text: "li::-moz-list-number", expected: "002"},
+    {text: "a:hover", expected: "011"},
+  ];
+
+  tests.forEach(function(aTest) {
+    let selector = new CssSelector(null, aTest.text);
+    let specificity = selector.specificity;
+
+    let result = "" + specificity.ids + specificity.classes + specificity.tags;
+    is(result, aTest.expected, "selector \"" + aTest.text +
+      "\" produces expected result");
+  });
+
+  finishUp();
+}
+
+function finishUp()
+{
+  CssLogic = CssSelector = null;
+  finish();
+}
new file mode 100644
--- /dev/null
+++ b/browser/devtools/styleinspector/test/browser_ruleview_editor_changedvalues.js
@@ -0,0 +1,190 @@
+/* vim: set ts=2 et sw=2 tw=80: */
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+let tempScope = {};
+Cu.import("resource:///modules/devtools/CssRuleView.jsm", tempScope);
+let CssRuleView = tempScope.CssRuleView;
+let _ElementStyle = tempScope._ElementStyle;
+let _editableField = tempScope._editableField;
+
+let doc;
+let ruleDialog;
+let ruleView;
+
+function waitForEditorFocus(aParent, aCallback)
+{
+  aParent.addEventListener("focus", function onFocus(evt) {
+    if (evt.target.inplaceEditor) {
+      aParent.removeEventListener("focus", onFocus, true);
+      let editor = evt.target.inplaceEditor;
+      executeSoon(function() {
+        aCallback(editor);
+      });
+    }
+  }, true);
+}
+
+function waitForEditorBlur(aEditor, aCallback)
+{
+  let input = aEditor.input;
+  input.addEventListener("blur", function onBlur() {
+    input.removeEventListener("blur", onBlur, false);
+    executeSoon(function() {
+      aCallback();
+    });
+  }, false);
+}
+
+var gRuleViewChanged = false;
+function ruleViewChanged()
+{
+  gRuleViewChanged = true;
+}
+
+function expectChange()
+{
+  ok(gRuleViewChanged, "Rule view should have fired a change event.");
+  gRuleViewChanged = false;
+}
+
+function startTest()
+{
+  let style = '' +
+    '#testid {' +
+    '  background-color: blue;' +
+    '} ' +
+    '.testclass {' +
+    '  background-color: green;' +
+    '}';
+
+  let styleNode = addStyle(doc, style);
+  doc.body.innerHTML = '<div id="testid" class="testclass">Styled Node</div>';
+  let testElement = doc.getElementById("testid");
+
+  ruleDialog = openDialog("chrome://browser/content/devtools/cssruleview.xul",
+                          "cssruleviewtest",
+                          "width=200,height=350");
+  ruleDialog.addEventListener("load", function onLoad(evt) {
+    ruleDialog.removeEventListener("load", onLoad, true);
+    let doc = ruleDialog.document;
+    ruleView = new CssRuleView(doc);
+    doc.documentElement.appendChild(ruleView.element);
+    ruleView.element.addEventListener("CssRuleViewChanged", ruleViewChanged, false);
+    ruleView.highlight(testElement);
+    waitForFocus(testCancelNew, ruleDialog);
+  }, true);
+}
+
+function testCancelNew()
+{
+  // Start at the beginning: start to add a rule to the element's style
+  // declaration, but leave it empty.
+
+  let elementRuleEditor = ruleView.element.children[0]._ruleEditor;
+  waitForEditorFocus(elementRuleEditor.element, function onNewElement(aEditor) {
+    is(elementRuleEditor.newPropSpan.inplaceEditor, aEditor, "Next focused editor should be the new property editor.");
+    let input = aEditor.input;
+    waitForEditorBlur(aEditor, function () {
+      ok(!gRuleViewChanged, "Shouldn't get a change event after a cancel.");
+      is(elementRuleEditor.rule.textProps.length,  0, "Should have canceled creating a new text property.");
+      ok(!elementRuleEditor.propertyList.hasChildNodes(), "Should not have any properties.");
+      testCreateNew();
+    });
+    aEditor.input.blur();
+  });
+
+  EventUtils.synthesizeMouse(elementRuleEditor.closeBrace, 1, 1,
+                             { },
+                             ruleDialog);
+}
+
+function testCreateNew()
+{
+  // Create a new property.
+  let elementRuleEditor = ruleView.element.children[0]._ruleEditor;
+  waitForEditorFocus(elementRuleEditor.element, function onNewElement(aEditor) {
+    is(elementRuleEditor.newPropSpan.inplaceEditor, aEditor, "Next focused editor should be the new property editor.");
+    let input = aEditor.input;
+    input.value = "background-color";
+
+    waitForEditorFocus(elementRuleEditor.element, function onNewValue(aEditor) {
+      expectChange();
+      is(elementRuleEditor.rule.textProps.length,  1, "Should have created a new text property.");
+      is(elementRuleEditor.propertyList.children.length, 1, "Should have created a property editor.");
+      let textProp = elementRuleEditor.rule.textProps[0];
+      is(aEditor, textProp.editor.valueSpan.inplaceEditor, "Should be editing the value span now.");
+
+      aEditor.input.value = "#XYZ";
+      waitForEditorBlur(aEditor, function() {
+        expectChange();
+        is(textProp.value, "#XYZ", "Text prop should have been changed.");
+        is(textProp.editor._validate(), false, "#XYZ should not be a valid entry");
+        testEditProperty();
+      });
+      aEditor.input.blur();
+    });
+    EventUtils.synthesizeKey("VK_RETURN", {}, ruleDialog);
+  });
+
+  EventUtils.synthesizeMouse(elementRuleEditor.closeBrace, 1, 1,
+                             { },
+                             ruleDialog);
+}
+
+function testEditProperty()
+{
+  let idRuleEditor = ruleView.element.children[1]._ruleEditor;
+  let propEditor = idRuleEditor.rule.textProps[0].editor;
+  waitForEditorFocus(propEditor.element, function onNewElement(aEditor) {
+    is(propEditor.nameSpan.inplaceEditor, aEditor, "Next focused editor should be the name editor.");
+    let input = aEditor.input;
+    waitForEditorFocus(propEditor.element, function onNewName(aEditor) {
+      expectChange();
+      input = aEditor.input;
+      is(propEditor.valueSpan.inplaceEditor, aEditor, "Focus should have moved to the value.");
+
+      waitForEditorBlur(aEditor, function() {
+        expectChange();
+        let value = idRuleEditor.rule.style.getPropertyValue("border-color");
+        is(value, "red", "border-color should have been set.");
+        is(propEditor._validate(), true, "red should be a valid entry");
+        finishTest();
+      });
+
+      for each (let ch in "red;") {
+        EventUtils.sendChar(ch, ruleDialog);
+      }
+    });
+    for each (let ch in "border-color:") {
+      EventUtils.sendChar(ch, ruleDialog);
+    }
+  });
+
+  EventUtils.synthesizeMouse(propEditor.nameSpan, 1, 1,
+                             { },
+                             ruleDialog);}
+
+function finishTest()
+{
+  ruleView.element.removeEventListener("CssRuleViewChanged", ruleViewChanged, false);
+  ruleView.clear();
+  ruleDialog.close();
+  ruleDialog = ruleView = null;
+  doc = null;
+  gBrowser.removeCurrentTab();
+  finish();
+}
+
+function test()
+{
+  waitForExplicitFinish();
+  gBrowser.selectedTab = gBrowser.addTab();
+  gBrowser.selectedBrowser.addEventListener("load", function changedValues_load(evt) {
+    gBrowser.selectedBrowser.removeEventListener(evt.type, changedValues_load, true);
+    doc = content.document;
+    waitForFocus(startTest, content);
+  }, true);
+
+  content.location = "data:text/html,test rule view user changes";
+}
--- a/browser/locales/en-US/chrome/browser/devtools/gclicommands.properties
+++ b/browser/locales/en-US/chrome/browser/devtools/gclicommands.properties
@@ -89,27 +89,27 @@ tiltTranslateManual=Incrementally transl
 # LOCALIZATION NOTE (tiltTranslateXDesc) A very short string to describe the
 # 'x' parameter to the 'tilt translate' command, which is displayed in a dialog
 # when the user is using this command.
 tiltTranslateXDesc=X (pixels)
 
 # LOCALIZATION NOTE (tiltTranslateXManual) A fuller description of the 'x'
 # parameter to the 'translate' command, displayed when the user asks for help
 # on what it does.
-tiltTranslateXManual=The ammount in pixels to translate the webpage mesh on the X axis
+tiltTranslateXManual=The amount in pixels to translate the webpage mesh on the X axis
 
 # LOCALIZATION NOTE (tiltTranslateYDesc) A very short string to describe the
 # 'y' parameter to the 'tilt translate' command, which is displayed in a dialog
 # when the user is using this command.
 tiltTranslateYDesc=Y (pixels)
 
 # LOCALIZATION NOTE (tiltTranslateYManual) A fuller description of the 'y'
 # parameter to the 'translate' command, displayed when the user asks for help
 # on what it does.
-tiltTranslateYManual=The ammount in pixels to translate the webpage mesh on the Y axis
+tiltTranslateYManual=The amount in pixels to translate the webpage mesh on the Y axis
 
 # LOCALIZATION NOTE (tiltRotateDesc) A very short description of the 'tilt rotate'
 # command. See tiltRotateManual for a fuller description of what it does. This
 # string is designed to be shown in a menu alongside the command name, which
 # is why it should be as short as possible.
 tiltRotateDesc=Spin the webpage mesh
 
 # LOCALIZATION NOTE (tiltRotateManual) A fuller description of the 'tilt rotate'
@@ -119,37 +119,37 @@ tiltRotateManual=Incrementally rotate th
 # LOCALIZATION NOTE (tiltRotateXDesc) A very short string to describe the
 # 'x' parameter to the 'tilt rotate' command, which is displayed in a dialog
 # when the user is using this command.
 tiltRotateXDesc=X (degrees)
 
 # LOCALIZATION NOTE (tiltRotateXManual) A fuller description of the 'x'
 # parameter to the 'rotate' command, displayed when the user asks for help
 # on what it does.
-tiltRotateXManual=The ammount in degrees to rotate the webpage mesh along the X axis
+tiltRotateXManual=The amount in degrees to rotate the webpage mesh along the X axis
 
 # LOCALIZATION NOTE (tiltRotateYDesc) A very short string to describe the
 # 'y' parameter to the 'tilt rotate' command, which is displayed in a dialog
 # when the user is using this command.
 tiltRotateYDesc=Y (degrees)
 
 # LOCALIZATION NOTE (tiltRotateYManual) A fuller description of the 'y'
 # parameter to the 'rotate' command, displayed when the user asks for help
 # on what it does.
-tiltRotateYManual=The ammount in degrees to rotate the webpage mesh along the Y axis
+tiltRotateYManual=The amount in degrees to rotate the webpage mesh along the Y axis
 
 # LOCALIZATION NOTE (tiltRotateZDesc) A very short string to describe the
 # 'z' parameter to the 'tilt rotate' command, which is displayed in a dialog
 # when the user is using this command.
 tiltRotateZDesc=Z (degrees)
 
 # LOCALIZATION NOTE (tiltRotateZManual) A fuller description of the 'z'
 # parameter to the 'rotate' command, displayed when the user asks for help
 # on what it does.
-tiltRotateZManual=The ammount in degrees to rotate the webpage mesh along the Z axis
+tiltRotateZManual=The amount in degrees to rotate the webpage mesh along the Z axis
 
 # LOCALIZATION NOTE (tiltZoomDesc) A very short description of the 'tilt zoom'
 # command. See tiltZoomManual for a fuller description of what it does. This
 # string is designed to be shown in a menu alongside the command name, which
 # is why it should be as short as possible.
 tiltZoomDesc=Move away or towards the webpage mesh
 
 # LOCALIZATION NOTE (tiltZoomManual) A fuller description of the 'tilt zoom'
--- a/browser/locales/en-US/chrome/browser/devtools/styleinspector.properties
+++ b/browser/locales/en-US/chrome/browser/devtools/styleinspector.properties
@@ -32,15 +32,20 @@ rule.sourceElement=element
 # e.g "Inherited from body#bodyID (styles.css:20)"
 rule.inheritedSource=Inherited from %S (%S)
 
 # LOCALIZATION NOTE (style.highlighter.button): These strings are used inside
 # sidebar of the Highlighter for the style inspector button.
 # "Computed" refers to the Computed Style of the element.
 style.highlighter.button.label2=Computed
 style.highlighter.accesskey2=C
-style.highlighter.button.tooltip=Inspect element computed styles
+style.highlighter.button.tooltip2=Inspect element computed styles
 
 # LOCALIZATION NOTE (helpLinkTitle): For each style property
 # the user can hover it and get a help link button which allows one to
 # quickly jump to the documentation from the Mozilla Developer Network site.
 # This is the link title shown in the hover tooltip.
 helpLinkTitle=Read the documentation for this property
+
+# LOCALIZATION NOTE (rule.warning.title): When an invalid property value is
+# entered into the rule view a warning icon is displayed. This text is used for
+# the title attribute of the warning icon.
+rule.warning.title=Invalid property value
new file mode 100644
index 0000000000000000000000000000000000000000..5c5d0aec58bd073334798117dc955d67edeb0276
GIT binary patch
literal 613
zc$@)c0-F7aP)<h;3K|Lk000e1NJLTq000dD000aK1^@s6xwkjj0000PbVXQnQ*UN;
zcVTj606}DLVr3vnZDD6+Qe|Oed2z{QJOBU!2T4RhRCwA{k;`inQ543{ea+m=BlAdN
z0wqyI+9H)!S5<c+T?j%Kii=`hsO_R?p^6JvrQ$|V6!9+*AGi>uf`VFf<6|RA(KdCV
z#wePkt!bJx$;{kw5~3s*4%`dh?>pyy2i=+60`1550T_i-x{9YO4w@M{_wt%*b#-W{
z-wp(Y5cJ1wd?}Trd`+lV)(cB%u1B8`D*xBv&Ncw53^R(MK}Fg6i7S$ueS3AfR$fus
zWf(QwTNONp!#eEOdxr1z9(sIQnES4awZ&aOKhB=$fc{;C0LjweY{Vi8;c7iFdA|Jp
z>kr8-v5jvJ##etWB|D(z=LwvQN7-J(Mi7$S-ub6D@bCFY1Eyty0-5dk#fM{^5I`zo
z;N#I4167wnRK6rCf3kz76;5(az&0q<va?4EnfLuoNCZTP!LfLZ?NkDQFb-}po$yv(
zT`+8|4+SGoiGjhFH|H1bjybg|X#~-2n|Q*CFd#C5nhQ`P$<MLABkx#zAYJ$T=J?@o
zV3wO3E#($=V}+xs#3m`ub=KGsR2{aVZyULp+;R9~v8<dguDV6xiXd4GF~ij|uP>j$
zVU3I$CIcoBKtW%bdZ9{oZqJ+B6WxUm_YYFv*Pyi$F4Mp@Jw(eMy_K)ZBjqB-tsrqJ
z_w0aJuMfsjUABXnmoE_qV}u-mJf!!$_$$BwV7{+%n+Ij`00000NkvXXu0mjf*SZsB
--- a/browser/themes/gnomestripe/devtools/csshtmltree.css
+++ b/browser/themes/gnomestripe/devtools/csshtmltree.css
@@ -212,16 +212,29 @@
 .ruleview-rule-source:hover {
   text-decoration: underline;
 }
 
 .ruleview-code {
   padding: 2px 5px;
 }
 
+.ruleview-warning {
+  background: url("chrome://browser/skin/devtools/alerticon-warning.png");
+  display: inline-block;
+  -moz-margin-start: 5px;
+  vertical-align: middle;
+  width: 13px;
+  height: 12px;
+}
+
+.ruleview-warning[hidden] {
+  display: none;
+}
+
 .ruleview-ruleopen {
   -moz-padding-end: 5px;
 }
 
 .ruleview-propertylist {
   list-style: none;
   padding: 0;
   margin: 0;
--- a/browser/themes/gnomestripe/devtools/debugger.css
+++ b/browser/themes/gnomestripe/devtools/debugger.css
@@ -111,18 +111,23 @@ a {
 /**
  * Stack frames
  */
 
 #stackframes {
   background-color: white;
 }
 
-.dbg-stackframe-id {
-  -moz-padding-end: 1em;
+.dbg-stackframe {
+  -moz-padding-start: 4px;
+  -moz-padding-end: 4px;
+}
+
+.dbg-stackframe-name {
+  font-weight: 600;
 }
 
 /**
  * Properties elements
  */
 
 #variables {
   background-color: white;
rename from browser/themes/gnomestripe/inspector.css
rename to browser/themes/gnomestripe/devtools/htmlpanel.css
--- a/browser/themes/gnomestripe/jar.mn
+++ b/browser/themes/gnomestripe/jar.mn
@@ -8,17 +8,16 @@ browser.jar:
   skin/classic/browser/aboutCertError.css             (aboutCertError.css)
 #ifdef MOZ_SERVICES_SYNC
   skin/classic/browser/aboutSyncTabs.css
 #endif
   skin/classic/browser/actionicon-tab.png
 * skin/classic/browser/browser.css                    (browser.css)
 * skin/classic/browser/engineManager.css              (engineManager.css)
   skin/classic/browser/fullscreen-video.css
-  skin/classic/browser/inspector.css
   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/Info.png
   skin/classic/browser/KUI-close.png
   skin/classic/browser/monitor.png
   skin/classic/browser/monitor_16-10.png
@@ -83,22 +82,24 @@ browser.jar:
   skin/classic/browser/tabview/edit-light.png         (tabview/edit-light.png)
   skin/classic/browser/tabview/search.png             (tabview/search.png)
   skin/classic/browser/tabview/stack-expander.png     (tabview/stack-expander.png)
   skin/classic/browser/tabview/tabview.png            (tabview/tabview.png)
   skin/classic/browser/tabview/tabview.css            (tabview/tabview.css)
   skin/classic/browser/devtools/common.css            (devtools/common.css)
   skin/classic/browser/devtools/arrows.png            (devtools/arrows.png)
   skin/classic/browser/devtools/commandline.png       (devtools/commandline.png)
+  skin/classic/browser/devtools/alerticon-warning.png (devtools/alerticon-warning.png)
   skin/classic/browser/devtools/goto-mdn.png          (devtools/goto-mdn.png)
   skin/classic/browser/devtools/csshtmltree.css       (devtools/csshtmltree.css)
   skin/classic/browser/devtools/webconsole.css                  (devtools/webconsole.css)
   skin/classic/browser/devtools/webconsole_networkpanel.css     (devtools/webconsole_networkpanel.css)
   skin/classic/browser/devtools/webconsole.png                  (devtools/webconsole.png)
   skin/classic/browser/devtools/gcli.css              (devtools/gcli.css)
+  skin/classic/browser/devtools/htmlpanel.css         (devtools/htmlpanel.css)
   skin/classic/browser/devtools/orion.css             (devtools/orion.css)
   skin/classic/browser/devtools/orion-container.css   (devtools/orion-container.css)
   skin/classic/browser/devtools/orion-task.png        (devtools/orion-task.png)
   skin/classic/browser/devtools/orion-breakpoint.png  (devtools/orion-breakpoint.png)
   skin/classic/browser/devtools/breadcrumbs/ltr-end-pressed.png              (devtools/breadcrumbs/ltr-end-pressed.png)
   skin/classic/browser/devtools/breadcrumbs/ltr-end-selected-pressed.png     (devtools/breadcrumbs/ltr-end-selected-pressed.png)
   skin/classic/browser/devtools/breadcrumbs/ltr-end-selected.png             (devtools/breadcrumbs/ltr-end-selected.png)
   skin/classic/browser/devtools/breadcrumbs/ltr-end.png                      (devtools/breadcrumbs/ltr-end.png)
new file mode 100644
index 0000000000000000000000000000000000000000..5c5d0aec58bd073334798117dc955d67edeb0276
GIT binary patch
literal 613
zc$@)c0-F7aP)<h;3K|Lk000e1NJLTq000dD000aK1^@s6xwkjj0000PbVXQnQ*UN;
zcVTj606}DLVr3vnZDD6+Qe|Oed2z{QJOBU!2T4RhRCwA{k;`inQ543{ea+m=BlAdN
z0wqyI+9H)!S5<c+T?j%Kii=`hsO_R?p^6JvrQ$|V6!9+*AGi>uf`VFf<6|RA(KdCV
z#wePkt!bJx$;{kw5~3s*4%`dh?>pyy2i=+60`1550T_i-x{9YO4w@M{_wt%*b#-W{
z-wp(Y5cJ1wd?}Trd`+lV)(cB%u1B8`D*xBv&Ncw53^R(MK}Fg6i7S$ueS3AfR$fus
zWf(QwTNONp!#eEOdxr1z9(sIQnES4awZ&aOKhB=$fc{;C0LjweY{Vi8;c7iFdA|Jp
z>kr8-v5jvJ##etWB|D(z=LwvQN7-J(Mi7$S-ub6D@bCFY1Eyty0-5dk#fM{^5I`zo
z;N#I4167wnRK6rCf3kz76;5(az&0q<va?4EnfLuoNCZTP!LfLZ?NkDQFb-}po$yv(
zT`+8|4+SGoiGjhFH|H1bjybg|X#~-2n|Q*CFd#C5nhQ`P$<MLABkx#zAYJ$T=J?@o
zV3wO3E#($=V}+xs#3m`ub=KGsR2{aVZyULp+;R9~v8<dguDV6xiXd4GF~ij|uP>j$
zVU3I$CIcoBKtW%bdZ9{oZqJ+B6WxUm_YYFv*Pyi$F4Mp@Jw(eMy_K)ZBjqB-tsrqJ
z_w0aJuMfsjUABXnmoE_qV}u-mJf!!$_$$BwV7{+%n+Ij`00000NkvXXu0mjf*SZsB
--- a/browser/themes/pinstripe/devtools/csshtmltree.css
+++ b/browser/themes/pinstripe/devtools/csshtmltree.css
@@ -214,16 +214,29 @@
 .ruleview-rule-source:hover {
   text-decoration: underline;
 }
 
 .ruleview-code {
   padding: 2px 5px;
 }
 
+.ruleview-warning {
+  background: url("chrome://browser/skin/devtools/alerticon-warning.png");
+  display: inline-block;
+  -moz-margin-start: 5px;
+  vertical-align: middle;
+  width: 13px;
+  height: 12px;
+}
+
+.ruleview-warning[hidden] {
+  display: none;
+}
+
 .ruleview-ruleopen {
   -moz-padding-end: 5px;
 }
 
 .ruleview-propertylist {
   list-style: none;
   padding: 0;
   margin: 0;
--- a/browser/themes/pinstripe/devtools/debugger.css
+++ b/browser/themes/pinstripe/devtools/debugger.css
@@ -115,18 +115,23 @@ a {
 /**
  * Stack frames
  */
 
 #stackframes {
   background-color: white;
 }
 
-.dbg-stackframe-id {
-  -moz-padding-end: 1em;
+.dbg-stackframe {
+  -moz-padding-start: 4px;
+  -moz-padding-end: 4px;
+}
+
+.dbg-stackframe-name {
+  font-weight: 600;
 }
 
 /**
  * Properties elements
  */
 
 #variables {
   background-color: white;
rename from browser/themes/pinstripe/inspector.css
rename to browser/themes/pinstripe/devtools/htmlpanel.css
--- a/browser/themes/pinstripe/jar.mn
+++ b/browser/themes/pinstripe/jar.mn
@@ -53,17 +53,16 @@ browser.jar:
   skin/classic/browser/feeds/videoFeedIcon.png              (feeds/feedIcon.png)
   skin/classic/browser/feeds/videoFeedIcon16.png            (feeds/feedIcon16.png)
   skin/classic/browser/feeds/audioFeedIcon.png              (feeds/feedIcon.png)
   skin/classic/browser/feeds/audioFeedIcon16.png            (feeds/feedIcon16.png)
   skin/classic/browser/newtab/newTab.css                    (newtab/newTab.css)
   skin/classic/browser/newtab/strip.png                     (newtab/strip.png)
   skin/classic/browser/newtab/toolbar.png                   (newtab/toolbar.png)
   skin/classic/browser/setDesktopBackground.css
-  skin/classic/browser/inspector.css
   skin/classic/browser/monitor.png
   skin/classic/browser/monitor_16-10.png
   skin/classic/browser/places/allBookmarks.png              (places/allBookmarks.png)
 * skin/classic/browser/places/places.css                    (places/places.css)
 * skin/classic/browser/places/organizer.css                 (places/organizer.css)
   skin/classic/browser/places/query.png                     (places/query.png)
   skin/classic/browser/places/bookmarksMenu.png             (places/bookmarksMenu.png)
   skin/classic/browser/places/bookmarksToolbar.png          (places/bookmarksToolbar.png)
@@ -122,19 +121,21 @@ browser.jar:
   skin/classic/browser/tabview/edit-light.png               (tabview/edit-light.png)
   skin/classic/browser/tabview/search.png                   (tabview/search.png)
   skin/classic/browser/tabview/stack-expander.png           (tabview/stack-expander.png)
   skin/classic/browser/tabview/tabview.png                  (tabview/tabview.png)
   skin/classic/browser/tabview/tabview.css                  (tabview/tabview.css)
 * skin/classic/browser/devtools/common.css                  (devtools/common.css)
   skin/classic/browser/devtools/arrows.png                  (devtools/arrows.png)
   skin/classic/browser/devtools/commandline.png             (devtools/commandline.png)
+  skin/classic/browser/devtools/alerticon-warning.png       (devtools/alerticon-warning.png)
   skin/classic/browser/devtools/goto-mdn.png                (devtools/goto-mdn.png)
   skin/classic/browser/devtools/csshtmltree.css             (devtools/csshtmltree.css)
   skin/classic/browser/devtools/gcli.css                    (devtools/gcli.css)
+  skin/classic/browser/devtools/htmlpanel.css               (devtools/htmlpanel.css)
   skin/classic/browser/devtools/orion.css                   (devtools/orion.css)
   skin/classic/browser/devtools/orion-container.css         (devtools/orion-container.css)
   skin/classic/browser/devtools/orion-task.png              (devtools/orion-task.png)
   skin/classic/browser/devtools/orion-breakpoint.png        (devtools/orion-breakpoint.png)
   skin/classic/browser/devtools/toolbarbutton-close.png     (devtools/toolbarbutton-close.png)
 * skin/classic/browser/devtools/webconsole.css                  (devtools/webconsole.css)
   skin/classic/browser/devtools/webconsole_networkpanel.css     (devtools/webconsole_networkpanel.css)
   skin/classic/browser/devtools/webconsole.png                  (devtools/webconsole.png)
@@ -160,20 +161,20 @@ browser.jar:
   skin/classic/browser/devtools/breadcrumbs/rtl-middle.png                   (devtools/breadcrumbs/rtl-middle.png)
   skin/classic/browser/devtools/breadcrumbs/rtl-start-pressed.png            (devtools/breadcrumbs/rtl-start-pressed.png)
   skin/classic/browser/devtools/breadcrumbs/rtl-start-selected-pressed.png   (devtools/breadcrumbs/rtl-start-selected-pressed.png)
   skin/classic/browser/devtools/breadcrumbs/rtl-start.png                    (devtools/breadcrumbs/rtl-start.png)
   skin/classic/browser/devtools/breadcrumbs/rtl-start-selected.png           (devtools/breadcrumbs/rtl-start-selected.png)
   skin/classic/browser/devtools/splitview.css               (devtools/splitview.css)
   skin/classic/browser/devtools/styleeditor.css             (devtools/styleeditor.css)
   skin/classic/browser/devtools/debugger.css                (devtools/debugger.css)
-  skin/classic/browser/devtools/magnifying-glass.png	    (devtools/magnifying-glass.png)
-  skin/classic/browser/devtools/itemToggle.png		    (devtools/itemToggle.png)
-  skin/classic/browser/devtools/itemArrow-rtl.png	    (devtools/itemArrow-rtl.png)
-  skin/classic/browser/devtools/itemArrow-ltr.png	    (devtools/itemArrow-ltr.png)
+  skin/classic/browser/devtools/magnifying-glass.png        (devtools/magnifying-glass.png)
+  skin/classic/browser/devtools/itemToggle.png              (devtools/itemToggle.png)
+  skin/classic/browser/devtools/itemArrow-rtl.png           (devtools/itemArrow-rtl.png)
+  skin/classic/browser/devtools/itemArrow-ltr.png           (devtools/itemArrow-ltr.png)
   skin/classic/browser/devtools/background-noise-toolbar.png (devtools/background-noise-toolbar.png)
 #ifdef MOZ_SERVICES_SYNC
   skin/classic/browser/sync-throbber.png
   skin/classic/browser/sync-16.png
   skin/classic/browser/sync-32.png
   skin/classic/browser/sync-bg.png
   skin/classic/browser/sync-128.png
   skin/classic/browser/sync-desktopIcon.png
new file mode 100644
index 0000000000000000000000000000000000000000..5c5d0aec58bd073334798117dc955d67edeb0276
GIT binary patch
literal 613
zc$@)c0-F7aP)<h;3K|Lk000e1NJLTq000dD000aK1^@s6xwkjj0000PbVXQnQ*UN;
zcVTj606}DLVr3vnZDD6+Qe|Oed2z{QJOBU!2T4RhRCwA{k;`inQ543{ea+m=BlAdN
z0wqyI+9H)!S5<c+T?j%Kii=`hsO_R?p^6JvrQ$|V6!9+*AGi>uf`VFf<6|RA(KdCV
z#wePkt!bJx$;{kw5~3s*4%`dh?>pyy2i=+60`1550T_i-x{9YO4w@M{_wt%*b#-W{
z-wp(Y5cJ1wd?}Trd`+lV)(cB%u1B8`D*xBv&Ncw53^R(MK}Fg6i7S$ueS3AfR$fus
zWf(QwTNONp!#eEOdxr1z9(sIQnES4awZ&aOKhB=$fc{;C0LjweY{Vi8;c7iFdA|Jp
z>kr8-v5jvJ##etWB|D(z=LwvQN7-J(Mi7$S-ub6D@bCFY1Eyty0-5dk#fM{^5I`zo
z;N#I4167wnRK6rCf3kz76;5(az&0q<va?4EnfLuoNCZTP!LfLZ?NkDQFb-}po$yv(
zT`+8|4+SGoiGjhFH|H1bjybg|X#~-2n|Q*CFd#C5nhQ`P$<MLABkx#zAYJ$T=J?@o
zV3wO3E#($=V}+xs#3m`ub=KGsR2{aVZyULp+;R9~v8<dguDV6xiXd4GF~ij|uP>j$
zVU3I$CIcoBKtW%bdZ9{oZqJ+B6WxUm_YYFv*Pyi$F4Mp@Jw(eMy_K)ZBjqB-tsrqJ
z_w0aJuMfsjUABXnmoE_qV}u-mJf!!$_$$BwV7{+%n+Ij`00000NkvXXu0mjf*SZsB
--- a/browser/themes/winstripe/devtools/csshtmltree.css
+++ b/browser/themes/winstripe/devtools/csshtmltree.css
@@ -212,16 +212,29 @@
 .ruleview-rule-source:hover {
   text-decoration: underline;
 }
 
 .ruleview-code {
   padding: 2px 5px;
 }
 
+.ruleview-warning {
+  background: url("chrome://browser/skin/devtools/alerticon-warning.png");
+  display: inline-block;
+  -moz-margin-start: 5px;
+  vertical-align: middle;
+  width: 13px;
+  height: 12px;
+}
+
+.ruleview-warning[hidden] {
+  display: none;
+}
+
 .ruleview-ruleopen {
   -moz-padding-end: 5px;
 }
 
 .ruleview-propertylist {
   list-style: none;
   padding: 0;
   margin: 0;
--- a/browser/themes/winstripe/devtools/debugger.css
+++ b/browser/themes/winstripe/devtools/debugger.css
@@ -111,18 +111,23 @@ a {
 /**
  * Stack frames
  */
 
 #stackframes {
   background-color: white;
 }
 
-.dbg-stackframe-id {
-  -moz-padding-end: 1em;
+.dbg-stackframe {
+  -moz-padding-start: 4px;
+  -moz-padding-end: 4px;
+}
+
+.dbg-stackframe-name {
+  font-weight: 600;
 }
 
 /**
  * Properties elements
  */
 
 #variables {
   background-color: white;
rename from browser/themes/winstripe/inspector.css
rename to browser/themes/winstripe/devtools/htmlpanel.css
--- a/browser/themes/winstripe/jar.mn
+++ b/browser/themes/winstripe/jar.mn
@@ -55,17 +55,16 @@ browser.jar:
         skin/classic/browser/feeds/audioFeedIcon16.png               (feeds/feedIcon16.png)
         skin/classic/browser/feeds/videoFeedIcon.png                 (feeds/feedIcon.png)
         skin/classic/browser/feeds/videoFeedIcon16.png               (feeds/feedIcon16.png)
         skin/classic/browser/feeds/subscribe.css                     (feeds/subscribe.css)
         skin/classic/browser/feeds/subscribe-ui.css                  (feeds/subscribe-ui.css)
         skin/classic/browser/newtab/newTab.css                       (newtab/newTab.css)
         skin/classic/browser/newtab/strip.png                        (newtab/strip.png)
         skin/classic/browser/newtab/toolbar.png                      (newtab/toolbar.png)
-        skin/classic/browser/inspector.css
         skin/classic/browser/places/places.css                       (places/places.css)
 *       skin/classic/browser/places/organizer.css                    (places/organizer.css)
         skin/classic/browser/places/bookmark.png                     (places/bookmark.png)
         skin/classic/browser/places/editBookmark.png                 (places/editBookmark.png)
         skin/classic/browser/places/query.png                        (places/query.png)
         skin/classic/browser/places/bookmarksMenu.png                (places/bookmarksMenu.png)
         skin/classic/browser/places/bookmarksToolbar.png             (places/bookmarksToolbar.png)
         skin/classic/browser/places/calendar.png                     (places/calendar.png)
@@ -107,19 +106,21 @@ browser.jar:
         skin/classic/browser/tabview/search.png                     (tabview/search.png)
         skin/classic/browser/tabview/stack-expander.png             (tabview/stack-expander.png)
         skin/classic/browser/tabview/tabview.png                    (tabview/tabview.png)
         skin/classic/browser/tabview/tabview-inverted.png           (tabview/tabview-inverted.png)
         skin/classic/browser/tabview/tabview.css                    (tabview/tabview.css)
         skin/classic/browser/devtools/common.css                    (devtools/common.css)
         skin/classic/browser/devtools/arrows.png                    (devtools/arrows.png)
         skin/classic/browser/devtools/commandline.png               (devtools/commandline.png)
+        skin/classic/browser/devtools/alerticon-warning.png         (devtools/alerticon-warning.png)
         skin/classic/browser/devtools/goto-mdn.png                  (devtools/goto-mdn.png)
         skin/classic/browser/devtools/csshtmltree.css               (devtools/csshtmltree.css)
         skin/classic/browser/devtools/gcli.css                      (devtools/gcli.css)
+        skin/classic/browser/devtools/htmlpanel.css                 (devtools/htmlpanel.css)
         skin/classic/browser/devtools/orion.css                     (devtools/orion.css)
         skin/classic/browser/devtools/orion-container.css           (devtools/orion-container.css)
         skin/classic/browser/devtools/orion-task.png                (devtools/orion-task.png)
         skin/classic/browser/devtools/orion-breakpoint.png          (devtools/orion-breakpoint.png)
         skin/classic/browser/devtools/toolbarbutton-close.png       (devtools/toolbarbutton-close.png)
         skin/classic/browser/devtools/webconsole.css                  (devtools/webconsole.css)
         skin/classic/browser/devtools/webconsole_networkpanel.css     (devtools/webconsole_networkpanel.css)
         skin/classic/browser/devtools/webconsole.png                  (devtools/webconsole.png)
@@ -224,17 +225,16 @@ browser.jar:
         skin/classic/aero/browser/feeds/audioFeedIcon16.png          (feeds/feedIcon16-aero.png)
         skin/classic/aero/browser/feeds/videoFeedIcon.png            (feeds/feedIcon-aero.png)
         skin/classic/aero/browser/feeds/videoFeedIcon16.png          (feeds/feedIcon16-aero.png)
         skin/classic/aero/browser/feeds/subscribe.css                (feeds/subscribe.css)
         skin/classic/aero/browser/feeds/subscribe-ui.css             (feeds/subscribe-ui.css)
         skin/classic/aero/browser/newtab/newTab.css                  (newtab/newTab.css)
         skin/classic/aero/browser/newtab/strip.png                   (newtab/strip.png)
         skin/classic/aero/browser/newtab/toolbar.png                 (newtab/toolbar.png)
-        skin/classic/aero/browser/inspector.css
 *       skin/classic/aero/browser/places/places.css                  (places/places-aero.css)
 *       skin/classic/aero/browser/places/organizer.css               (places/organizer-aero.css)
         skin/classic/aero/browser/places/bookmark.png                (places/bookmark.png)
         skin/classic/aero/browser/places/editBookmark.png            (places/editBookmark.png)
         skin/classic/aero/browser/places/query.png                   (places/query-aero.png)
         skin/classic/aero/browser/places/bookmarksMenu.png           (places/bookmarksMenu-aero.png)
         skin/classic/aero/browser/places/bookmarksToolbar.png        (places/bookmarksToolbar-aero.png)
         skin/classic/aero/browser/places/calendar.png                (places/calendar-aero.png)
@@ -276,19 +276,21 @@ browser.jar:
         skin/classic/aero/browser/tabview/search.png                 (tabview/search.png)
         skin/classic/aero/browser/tabview/stack-expander.png         (tabview/stack-expander.png)
         skin/classic/aero/browser/tabview/tabview.png                (tabview/tabview.png)
         skin/classic/aero/browser/tabview/tabview-inverted.png       (tabview/tabview-inverted.png)
         skin/classic/aero/browser/tabview/tabview.css                (tabview/tabview.css)
         skin/classic/aero/browser/devtools/common.css                (devtools/common.css)
         skin/classic/aero/browser/devtools/arrows.png                (devtools/arrows.png)
         skin/classic/aero/browser/devtools/commandline.png           (devtools/commandline.png)
+        skin/classic/aero/browser/devtools/alerticon-warning.png     (devtools/alerticon-warning.png)
         skin/classic/aero/browser/devtools/goto-mdn.png              (devtools/goto-mdn.png)
         skin/classic/aero/browser/devtools/csshtmltree.css           (devtools/csshtmltree.css)
         skin/classic/aero/browser/devtools/gcli.css                  (devtools/gcli.css)
+        skin/classic/aero/browser/devtools/htmlpanel.css             (devtools/htmlpanel.css)
         skin/classic/aero/browser/devtools/orion.css                 (devtools/orion.css)
         skin/classic/aero/browser/devtools/orion-container.css       (devtools/orion-container.css)
         skin/classic/aero/browser/devtools/orion-task.png            (devtools/orion-task.png)
         skin/classic/aero/browser/devtools/orion-breakpoint.png      (devtools/orion-breakpoint.png)
         skin/classic/aero/browser/devtools/toolbarbutton-close.png   (devtools/toolbarbutton-close.png)
         skin/classic/aero/browser/devtools/webconsole.css                  (devtools/webconsole.css)
         skin/classic/aero/browser/devtools/webconsole_networkpanel.css     (devtools/webconsole_networkpanel.css)
         skin/classic/aero/browser/devtools/webconsole.png                  (devtools/webconsole.png)