merge m-c to fx-team
authorTim Taubert <tim.taubert@gmx.de>
Fri, 02 Mar 2012 09:47:01 +0100
changeset 88263 a48a08ecd5c16d4a148b9266b7f58fc7fa117f39
parent 88252 3a7b9e61c26342f4fa46deb7f37cc6f6b389c00a (current diff)
parent 88262 937133553156838ee67a19f28b40acb693bdb67a (diff)
child 88338 343ec916dfd526957ecff6b224d00634be856dd9
child 88412 5724c5ba0f84ef3e2928717e7900c9e11e3d1c13
push id157
push userMs2ger@gmail.com
push dateWed, 07 Mar 2012 19:27:10 +0000
milestone13.0a1
merge m-c to fx-team
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 e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..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 e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..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 e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..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)