Backed out 6 changesets (bug 663778) for browser_dbg_listtabs-02.js leaks on a CLOSED TREE.
authorRyan VanderMeulen <ryanvm@gmail.com>
Thu, 13 Mar 2014 13:56:22 -0400
changeset 173401 583b3de7f71a70d37433da99f684254b0ed1961a
parent 173400 f33b136050106e4dec3d27b6df3474b84ec4b4fd
child 173472 5efe0f428d4b2b4cb4936e201527b2cc27eecfc2
push id5671
push userryanvm@gmail.com
push dateThu, 13 Mar 2014 17:55:51 +0000
treeherderfx-team@583b3de7f71a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs663778
milestone30.0a1
backs outcbd200206f9b9ee97b7a38ad3deea33b4b68e7ad
b0b74401e6140002fb08e0fa4f5d6bd1d5c576f6
df5255cffbfae3bfa642aad3cb6ac0777972c4dc
e6d0dd1243565be0bc0b127d2e59506370d2f724
134f774749413c953d7378e4cdb44b66c7fa8341
456609873c5f08acf34e341f3f3b653a0312f872
Backed out 6 changesets (bug 663778) for browser_dbg_listtabs-02.js leaks on a CLOSED TREE. Backed out changeset cbd200206f9b (bug 663778) Backed out changeset b0b74401e614 (bug 663778) Backed out changeset df5255cffbfa (bug 663778) Backed out changeset e6d0dd124356 (bug 663778) Backed out changeset 134f77474941 (bug 663778) Backed out changeset 456609873c5f (bug 663778)
browser/base/content/browser.css
browser/base/content/highlighter.css
browser/base/content/test/general/domplate_test.js
browser/devtools/app-manager/test/head.js
browser/devtools/commandline/test/head.js
browser/devtools/debugger/test/browser_dbg_variables-view-frame-with.js
browser/devtools/debugger/test/head.js
browser/devtools/fontinspector/test/browser_fontinspector.js
browser/devtools/framework/gDevTools.jsm
browser/devtools/framework/selection.js
browser/devtools/framework/test/head.js
browser/devtools/framework/toolbox.js
browser/devtools/inspector/breadcrumbs.js
browser/devtools/inspector/test/browser_inspector_basic_highlighter.js
browser/devtools/inspector/test/browser_inspector_breadcrumbs.js
browser/devtools/inspector/test/browser_inspector_bug_650804_search.js
browser/devtools/inspector/test/browser_inspector_bug_674871.js
browser/devtools/inspector/test/browser_inspector_bug_699308_iframe_navigation.js
browser/devtools/inspector/test/browser_inspector_bug_958456_highlight_comments.js
browser/devtools/inspector/test/browser_inspector_changes.js
browser/devtools/inspector/test/browser_inspector_highlighter.js
browser/devtools/inspector/test/browser_inspector_iframeTest.js
browser/devtools/inspector/test/browser_inspector_initialization.js
browser/devtools/inspector/test/browser_inspector_invalidate.js
browser/devtools/inspector/test/browser_inspector_scrolling.js
browser/devtools/inspector/test/browser_inspector_sidebarstate.js
browser/devtools/inspector/test/browser_inspector_tree_height.js
browser/devtools/inspector/test/head.js
browser/devtools/layoutview/test/browser_layoutview.js
browser/devtools/layoutview/view.css
browser/devtools/layoutview/view.js
browser/devtools/layoutview/view.xhtml
browser/devtools/markupview/markup-view.js
browser/devtools/markupview/test/browser_inspector_markup_968316_highlight_node_after_mouseleave_mousemove.js
browser/devtools/markupview/test/browser_inspector_markup_968316_highlit_node_on_hover_then_select.js
browser/devtools/markupview/test/browser_inspector_markup_navigation.js
browser/devtools/markupview/test/head.js
browser/devtools/netmonitor/test/head.js
browser/devtools/profiler/test/head.js
browser/devtools/responsivedesign/test/head.js
browser/devtools/scratchpad/test/browser_scratchpad_revert_to_saved.js
browser/devtools/scratchpad/test/head.js
browser/devtools/shared/test/head.js
browser/devtools/sourceeditor/editor.js
browser/devtools/sourceeditor/test/head.js
browser/devtools/styleeditor/test/head.js
browser/devtools/styleinspector/style-inspector.js
browser/devtools/styleinspector/test/browser_ruleview_inherit.js
browser/devtools/styleinspector/test/browser_ruleview_manipulation.js
browser/devtools/styleinspector/test/browser_ruleview_override.js
browser/devtools/styleinspector/test/browser_ruleview_ui.js
browser/devtools/styleinspector/test/browser_ruleview_update.js
browser/devtools/styleinspector/test/head.js
browser/devtools/tilt/test/head.js
browser/devtools/webconsole/test/browser_console_variables_view_highlighter.js
browser/devtools/webconsole/test/browser_webconsole_autocomplete_in_debugger_stackframe.js
browser/devtools/webconsole/test/browser_webconsole_bug_585991_autocomplete_keys.js
browser/devtools/webconsole/test/browser_webconsole_bug_651501_document_body_autocomplete.js
browser/devtools/webconsole/test/browser_webconsole_output_01.js
browser/devtools/webconsole/test/browser_webconsole_output_03.js
browser/devtools/webconsole/test/browser_webconsole_view_source.js
browser/devtools/webconsole/test/head.js
browser/themes/linux/browser.css
browser/themes/linux/devtools/layoutview.css
browser/themes/osx/browser.css
browser/themes/osx/devtools/layoutview.css
browser/themes/shared/devtools/highlighter.inc.css
browser/themes/windows/browser.css
browser/themes/windows/devtools/layoutview.css
toolkit/devtools/LayoutHelpers.jsm
toolkit/devtools/server/actors/highlighter.js
toolkit/devtools/server/actors/inspector.js
--- a/browser/base/content/browser.css
+++ b/browser/base/content/browser.css
@@ -1,15 +1,14 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 @namespace url("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul");
 @namespace html url("http://www.w3.org/1999/xhtml");
-@namespace svg url("http://www.w3.org/2000/svg");
 
 #main-window:not([chromehidden~="toolbar"]) {
 %ifdef XP_MACOSX
   min-width: 335px;
 %else
   min-width: 300px;
 %endif
 }
--- a/browser/base/content/highlighter.css
+++ b/browser/base/content/highlighter.css
@@ -1,25 +1,35 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 .highlighter-container {
   pointer-events: none;
 }
 
-/*
- * Box model highlighter
- */
-svg|svg.box-model-root[hidden],
-svg|line.box-model-guide-top[hidden],
-svg|line.box-model-guide-right[hidden],
-svg|line.box-model-guide-left[hidden],
-svg|line.box-model-guide-bottom[hidden] {
-  display: none;
+.highlighter-outline-container {
+  overflow: hidden;
+  position: relative;
+}
+
+.highlighter-outline {
+  position: absolute;
+}
+
+.highlighter-outline[hidden] {
+  opacity: 0;
+  pointer-events: none;
+  display: -moz-box;
+}
+
+.highlighter-outline:not([disable-transitions]) {
+  transition-property: opacity, top, left, width, height;
+  transition-duration: 0.1s;
+  transition-timing-function: linear;
 }
 
 /*
  * Node Infobar
  */
 .highlighter-nodeinfobar-container {
   position: relative;
 }
@@ -30,16 +40,23 @@ svg|line.box-model-guide-bottom[hidden] 
 }
 
 .highlighter-nodeinfobar-positioner[hidden] {
   opacity: 0;
   pointer-events: none;
   display: -moz-box;
 }
 
+.highlighter-nodeinfobar-positioner:not([disable-transitions]),
+.highlighter-nodeinfobar-positioner[disable-transitions][force-transitions] {
+  transition-property: transform, opacity, top, left;
+  transition-duration: 0.1s;
+  transition-timing-function: linear;
+}
+
 .highlighter-nodeinfobar-text {
   overflow: hidden;
   white-space: nowrap;
   text-overflow: ellipsis;
   direction: ltr;
 }
 
 html|*.highlighter-nodeinfobar-id,
--- a/browser/base/content/test/general/domplate_test.js
+++ b/browser/base/content/test/general/domplate_test.js
@@ -41,11 +41,11 @@ function test()
   waitForExplicitFinish();
   gBrowser.selectedTab = gBrowser.addTab();
   gBrowser.selectedBrowser.addEventListener("load", function() {
     gBrowser.selectedBrowser.removeEventListener("load", arguments.callee, true);
     doc = content.document;
     waitForFocus(createDocument, content);
   }, true);
 
-  content.location = "data:text/html;charset=utf-8,domplate_test.js";
+  content.location = "data:text/html,basic domplate tests";
 }
 
--- a/browser/devtools/app-manager/test/head.js
+++ b/browser/devtools/app-manager/test/head.js
@@ -14,21 +14,16 @@ const {AppProjects} = require("devtools/
 
 const APP_MANAGER_URL = "about:app-manager";
 const TEST_BASE =
   "chrome://mochitests/content/browser/browser/devtools/app-manager/test/";
 const HOSTED_APP_MANIFEST = TEST_BASE + "hosted_app.manifest";
 
 const PACKAGED_APP_DIR_PATH = getTestFilePath(".");
 
-gDevTools.testing = true;
-SimpleTest.registerCleanupFunction(() => {
-  gDevTools.testing = false;
-});
-
 function addTab(url, targetWindow = window) {
   info("Adding tab: " + url);
 
   let deferred = promise.defer();
   let targetBrowser = targetWindow.gBrowser;
 
   targetWindow.focus();
   let tab = targetBrowser.selectedTab = targetBrowser.addTab(url);
--- a/browser/devtools/commandline/test/head.js
+++ b/browser/devtools/commandline/test/head.js
@@ -5,21 +5,16 @@
 const TEST_BASE_HTTP = "http://example.com/browser/browser/devtools/commandline/test/";
 const TEST_BASE_HTTPS = "https://example.com/browser/browser/devtools/commandline/test/";
 
 // Import the GCLI test helper
 let testDir = gTestPath.substr(0, gTestPath.lastIndexOf("/"));
 Services.scriptloader.loadSubScript(testDir + "/helpers.js", this);
 Services.scriptloader.loadSubScript(testDir + "/mockCommands.js", this);
 
-gDevTools.testing = true;
-SimpleTest.registerCleanupFunction(() => {
-  gDevTools.testing = false;
-});
-
 function whenDelayedStartupFinished(aWindow, aCallback) {
   Services.obs.addObserver(function observer(aSubject, aTopic) {
     if (aWindow == aSubject) {
       Services.obs.removeObserver(observer, aTopic);
       executeSoon(aCallback);
     }
   }, "browser-delayed-startup-finished", false);
 }
--- a/browser/devtools/debugger/test/browser_dbg_variables-view-frame-with.js
+++ b/browser/devtools/debugger/test/browser_dbg_variables-view-frame-with.js
@@ -202,10 +202,9 @@ function testFunctionScope() {
     "Should have the right token class for 'foo'.");
 }
 
 registerCleanupFunction(function() {
   gTab = null;
   gDebuggee = null;
   gPanel = null;
   gDebugger = null;
-  gVariables = null;
 });
--- a/browser/devtools/debugger/test/head.js
+++ b/browser/devtools/debugger/test/head.js
@@ -22,21 +22,16 @@ let { BrowserToolboxProcess } = Cu.impor
 let { DebuggerServer } = Cu.import("resource://gre/modules/devtools/dbg-server.jsm", {});
 let { DebuggerClient } = Cu.import("resource://gre/modules/devtools/dbg-client.jsm", {});
 let { AddonManager } = Cu.import("resource://gre/modules/AddonManager.jsm", {});
 let TargetFactory = devtools.TargetFactory;
 let Toolbox = devtools.Toolbox;
 
 const EXAMPLE_URL = "http://example.com/browser/browser/devtools/debugger/test/";
 
-gDevTools.testing = true;
-SimpleTest.registerCleanupFunction(() => {
-  gDevTools.testing = false;
-});
-
 // All tests are asynchronous.
 waitForExplicitFinish();
 
 registerCleanupFunction(function() {
   info("finish() was called, cleaning up...");
   Services.prefs.setBoolPref("devtools.debugger.log", gEnableLogging);
 
   // Properly shut down the server to avoid memory leaks.
--- a/browser/devtools/fontinspector/test/browser_fontinspector.js
+++ b/browser/devtools/fontinspector/test/browser_fontinspector.js
@@ -11,21 +11,16 @@ let DOMUtils = Cc["@mozilla.org/inspecto
 function test() {
   waitForExplicitFinish();
 
   let doc;
   let view;
   let viewDoc;
   let inspector;
 
-  gDevTools.testing = true;
-  SimpleTest.registerCleanupFunction(() => {
-    gDevTools.testing = false;
-  });
-
   gBrowser.selectedTab = gBrowser.addTab();
   gBrowser.selectedBrowser.addEventListener("load", function onload() {
     gBrowser.selectedBrowser.removeEventListener("load", onload, true);
     doc = content.document;
     waitForFocus(setupTest, content);
   }, true);
 
   content.location = "http://mochi.test:8888/browser/browser/devtools/fontinspector/test/browser_fontinspector.html";
--- a/browser/devtools/framework/gDevTools.jsm
+++ b/browser/devtools/framework/gDevTools.jsm
@@ -27,49 +27,24 @@ const MAX_ORDINAL = 99;
 this.DevTools = function DevTools() {
   this._tools = new Map();     // Map<toolId, tool>
   this._toolboxes = new Map(); // Map<target, toolbox>
 
   // destroy() is an observer's handler so we need to preserve context.
   this.destroy = this.destroy.bind(this);
   this._teardown = this._teardown.bind(this);
 
-  this._testing = false;
-
   EventEmitter.decorate(this);
 
   Services.obs.addObserver(this._teardown, "devtools-unloaded", false);
   Services.obs.addObserver(this.destroy, "quit-application", false);
 }
 
 DevTools.prototype = {
   /**
-   * When the testing flag is set we take appropriate action to prevent race
-   * conditions in our testing environment. This means setting
-   * dom.send_after_paint_to_content to false to prevent infinite MozAfterPaint
-   * loops and not autohiding the highlighter.
-   */
-  get testing() {
-    return this._testing;
-  },
-
-  set testing(state) {
-    this._testing = state;
-
-    if (state) {
-      // dom.send_after_paint_to_content is set to true (non-default) in
-      // testing/profiles/prefs_general.js so lets set it to the same as it is
-      // in a default browser profile for the duration of the test.
-      Services.prefs.setBoolPref("dom.send_after_paint_to_content", false);
-    } else {
-      Services.prefs.setBoolPref("dom.send_after_paint_to_content", true);
-    }
-  },
-
-  /**
    * Register a new developer tool.
    *
    * A definition is a light object that holds different information about a
    * developer tool. This object is not supposed to have any operational code.
    * See it as a "manifest".
    * The only actual code lives in the build() function, which will be used to
    * start an instance of this tool.
    *
--- a/browser/devtools/framework/selection.js
+++ b/browser/devtools/framework/selection.js
@@ -155,32 +155,30 @@ Selection.prototype = {
     if (this.isNode()) {
       return this.node.ownerDocument;
     }
     return null;
   },
 
   setNodeFront: function(value, reason="unknown") {
     this.reason = reason;
-
-    // We used to return here if the node had not changed but we now need to
-    // set the node even if it is already set otherwise it is not possible to
-    // e.g. highlight the same node twice.
-    let rawValue = null;
-    if (value && value.isLocal_toBeDeprecated()) {
-      rawValue = value.rawNode();
+    if (value !== this._nodeFront) {
+      let rawValue = null;
+      if (value && value.isLocal_toBeDeprecated()) {
+        rawValue = value.rawNode();
+      }
+      this.emit("before-new-node", rawValue, reason);
+      this.emit("before-new-node-front", value, reason);
+      let previousNode = this._node;
+      let previousFront = this._nodeFront;
+      this._node = rawValue;
+      this._nodeFront = value;
+      this.emit("new-node", previousNode, this.reason);
+      this.emit("new-node-front", value, this.reason);
     }
-    this.emit("before-new-node", rawValue, reason);
-    this.emit("before-new-node-front", value, reason);
-    let previousNode = this._node;
-    let previousFront = this._nodeFront;
-    this._node = rawValue;
-    this._nodeFront = value;
-    this.emit("new-node", previousNode, this.reason);
-    this.emit("new-node-front", value, this.reason);
   },
 
   get documentFront() {
     return this._walker.document(this._nodeFront);
   },
 
   get nodeFront() {
     return this._nodeFront;
--- a/browser/devtools/framework/test/head.js
+++ b/browser/devtools/framework/test/head.js
@@ -8,21 +8,16 @@ let tempScope = {};
 Components.utils.import("resource://gre/modules/devtools/Console.jsm", tempScope);
 let console = tempScope.console;
 Components.utils.import("resource://gre/modules/commonjs/sdk/core/promise.js", tempScope);
 let promise = tempScope.Promise;
 
 let {devtools} = Components.utils.import("resource://gre/modules/devtools/Loader.jsm", {});
 let TargetFactory = devtools.TargetFactory;
 
-gDevTools.testing = true;
-SimpleTest.registerCleanupFunction(() => {
-  gDevTools.testing = false;
-});
-
 /**
  * Open a new tab at a URL and call a callback on load
  */
 function addTab(aURL, aCallback)
 {
   waitForExplicitFinish();
 
   gBrowser.selectedTab = gBrowser.addTab();
--- a/browser/devtools/framework/toolbox.js
+++ b/browser/devtools/framework/toolbox.js
@@ -68,18 +68,16 @@ function Toolbox(target, selectedTool, h
   this._telemetry = new Telemetry();
 
   this._toolRegistered = this._toolRegistered.bind(this);
   this._toolUnregistered = this._toolUnregistered.bind(this);
   this._refreshHostTitle = this._refreshHostTitle.bind(this);
   this._splitConsoleOnKeypress = this._splitConsoleOnKeypress.bind(this)
   this.destroy = this.destroy.bind(this);
   this.highlighterUtils = new ToolboxHighlighterUtils(this);
-  this._highlighterReady = this._highlighterReady.bind(this);
-  this._highlighterHidden = this._highlighterHidden.bind(this);
 
   this._target.on("close", this.destroy);
 
   if (!hostType) {
     hostType = Services.prefs.getCharPref(this._prefs.LAST_HOST);
   }
   if (!selectedTool) {
     selectedTool = Services.prefs.getCharPref(this._prefs.LAST_TOOL);
@@ -1094,72 +1092,55 @@ Toolbox.prototype = {
    * Returns a promise that resolves when the fronts are initialized
    */
   initInspector: function() {
     if (!this._initInspector) {
       this._initInspector = Task.spawn(function*() {
         this._inspector = InspectorFront(this._target.client, this._target.form);
         this._walker = yield this._inspector.getWalker();
         this._selection = new Selection(this._walker);
-
         if (this.highlighterUtils.isRemoteHighlightable) {
-          let autohide = !gDevTools.testing;
-
-          this.walker.on("highlighter-ready", this._highlighterReady);
-          this.walker.on("highlighter-hide", this._highlighterHidden);
-
-          this._highlighter = yield this._inspector.getHighlighter(autohide);
+          this._highlighter = yield this._inspector.getHighlighter();
         }
       }.bind(this));
     }
     return this._initInspector;
   },
 
   /**
    * Destroy the inspector/walker/selection fronts
    * Returns a promise that resolves when the fronts are destroyed
    */
   destroyInspector: function() {
-    if (this._destroying) {
-      return this._destroying;
-    }
-
     if (!this._inspector) {
       return promise.resolve();
     }
 
     let outstanding = () => {
       return Task.spawn(function*() {
         yield this.highlighterUtils.stopPicker();
         yield this._inspector.destroy();
         if (this._highlighter) {
           yield this._highlighter.destroy();
         }
         if (this._selection) {
           this._selection.destroy();
         }
 
-        if (this.walker) {
-          this.walker.off("highlighter-ready", this._highlighterReady);
-          this.walker.off("highlighter-hide", this._highlighterHidden);
-        }
-
         this._inspector = null;
         this._highlighter = null;
         this._selection = null;
         this._walker = null;
       }.bind(this));
     };
 
     // Releasing the walker (if it has been created)
     // This can fail, but in any case, we want to continue destroying the
     // inspector/highlighter/selection
-    let walker = (this._destroying = this._walker) ?
-                 this._walker.release() :
-                 promise.resolve();
+    let walker = this._walker ? this._walker.release() : promise.resolve();
     return walker.then(outstanding, outstanding);
   },
 
   /**
    * Get the toolbox's notification box
    *
    * @return The notification box element.
    */
@@ -1238,25 +1219,17 @@ Toolbox.prototype = {
       return target.destroy();
     }).then(() => {
       this.emit("destroyed");
       // Free _host after the call to destroyed in order to let a chance
       // to destroyed listeners to still query toolbox attributes
       this._host = null;
       this._toolPanels.clear();
     }).then(null, console.error);
-  },
-
-  _highlighterReady: function() {
-    this.emit("highlighter-ready");
-  },
-
-  _highlighterHidden: function() {
-    this.emit("highlighter-hide");
-  },
+  }
 };
 
 /**
  * The ToolboxHighlighterUtils is what you should use for anything related to
  * node highlighting and picking.
  * It encapsulates the logic to connecting to the HighlighterActor.
  */
 function ToolboxHighlighterUtils(toolbox) {
@@ -1306,40 +1279,39 @@ ToolboxHighlighterUtils.prototype = {
   startPicker: function() {
     if (this._isPicking) {
       return promise.resolve();
     }
 
     let deferred = promise.defer();
 
     let done = () => {
-      this._isPicking = true;
       this.toolbox.emit("picker-started");
       this.toolbox.on("select", this.stopPicker);
       deferred.resolve();
     };
 
     promise.all([
       this.toolbox.initInspector(),
       this.toolbox.selectTool("inspector")
     ]).then(() => {
+      this._isPicking = true;
       this.toolbox._pickerButton.setAttribute("checked", "true");
 
       if (this.isRemoteHighlightable) {
+        this.toolbox.highlighter.pick().then(done);
+
         this.toolbox.walker.on("picker-node-hovered", this._onPickerNodeHovered);
         this.toolbox.walker.on("picker-node-picked", this._onPickerNodePicked);
-
-        this.toolbox.highlighter.pick().then(done);
       } else {
-        return this.toolbox.walker.pick().then(node => {
-          this.toolbox.selection.setNodeFront(node, "picker-node-picked").then(() => {
-            this.stopPicker();
-            done();
-          });
+        this.toolbox.walker.pick().then(node => {
+          this.toolbox.selection.setNodeFront(node, "picker-node-picked");
+          this.stopPicker();
         });
+        done();
       }
     });
 
     return deferred.promise;
   },
 
   /**
    * Stop the element picker
@@ -1427,26 +1399,21 @@ ToolboxHighlighterUtils.prototype = {
       return this.toolbox.walker.getNodeActorFromObjectActor(grip.actor);
     });
   },
 
   /**
    * Hide the highlighter.
    * @return a promise that resolves when the highlighter is hidden
    */
-  unhighlight: function(forceHide=false) {
+  unhighlight: function() {
     if (this.isRemoteHighlightable) {
       // If the remote highlighter exists on the target, use it
       return this.toolbox.initInspector().then(() => {
-        let autohide = forceHide || !gDevTools.testing;
-
-        if (autohide) {
-          return this.toolbox.highlighter.hideBoxModel();
-        }
-        return promise.resolve();
+        return this.toolbox.highlighter.hideBoxModel();
       });
     } else {
       // If not, no need to unhighlight as the older highlight method uses a
       // setTimeout to hide itself
       return promise.resolve();
     }
   }
 };
--- a/browser/devtools/inspector/breadcrumbs.js
+++ b/browser/devtools/inspector/breadcrumbs.js
@@ -694,13 +694,13 @@ HTMLBreadcrumbs.prototype = {
       this.scroll();
       this.inspector.emit("breadcrumbs-updated", this.selection.nodeFront);
       doneUpdating();
     }).then(null, err => {
       doneUpdating(this.selection.nodeFront);
       this.selectionGuardEnd(err);
     });
   }
-};
+}
 
 XPCOMUtils.defineLazyGetter(this, "DOMUtils", function () {
   return Cc["@mozilla.org/inspector/dom-utils;1"].getService(Ci.inIDOMUtils);
 });
--- a/browser/devtools/inspector/test/browser_inspector_basic_highlighter.js
+++ b/browser/devtools/inspector/test/browser_inspector_basic_highlighter.js
@@ -13,50 +13,72 @@ function test() {
 
   gBrowser.selectedTab = gBrowser.addTab();
   gBrowser.selectedBrowser.addEventListener("load", function onload() {
     gBrowser.selectedBrowser.removeEventListener("load", onload, true);
     doc = content.document;
     waitForFocus(setupTest, content);
   }, true);
 
-  content.location = "data:text/html;charset=utf-8,<h1>foo</h1><span>bar</span>";
+  content.location = "data:text/html,<h1>foo</h1><h2>bar</h2>";
 
   function setupTest() {
     openInspector((aInspector, aToolbox) => {
       toolbox = aToolbox;
       inspector = aInspector;
-      inspector.selection.setNode(doc.querySelector("span"), "test");
-      inspector.toolbox.once("highlighter-ready", runTests);
+      inspector.selection.setNode(doc.querySelector("h2"), null);
+      inspector.once("inspector-updated", runTests);
     });
   }
 
-  function runTests() {
+  function runTests(aInspector) {
+    getHighlighterOutline().setAttribute("disable-transitions", "true");
     Task.spawn(function() {
       yield hoverH1InMarkupView();
       yield assertH1Highlighted();
+      yield mouseLeaveMarkupView();
+      yield assertNoNodeHighlighted();
 
       finishUp();
     }).then(null, Cu.reportError);
   }
 
   function hoverH1InMarkupView() {
     let deferred = promise.defer();
+
     let container = getContainerForRawNode(inspector.markup, doc.querySelector("h1"));
-
-    inspector.toolbox.once("highlighter-ready", deferred.resolve);
-    EventUtils.synthesizeMouseAtCenter(container.tagLine, {type: "mousemove"},
-                                       inspector.markup.doc.defaultView);
+    EventUtils.synthesizeMouse(container.tagLine, 2, 2, {type: "mousemove"},
+      inspector.markup.doc.defaultView);
+    inspector.toolbox.once("node-highlight", deferred.resolve);
 
     return deferred.promise;
   }
 
   function assertH1Highlighted() {
     ok(isHighlighting(), "The highlighter is shown on a markup container hover");
     is(getHighlitNode(), doc.querySelector("h1"), "The highlighter highlights the right node");
+    return promise.resolve();
+  }
+
+  function mouseLeaveMarkupView() {
+    let deferred = promise.defer();
+
+    // Find another element to mouseover over in order to leave the markup-view
+    let btn = toolbox.doc.querySelector(".toolbox-dock-button");
+
+    EventUtils.synthesizeMouse(btn, 2, 2, {type: "mousemove"},
+      toolbox.doc.defaultView);
+    executeSoon(deferred.resolve);
+
+    return deferred.promise;
+  }
+
+  function assertNoNodeHighlighted() {
+    ok(!isHighlighting(), "After the mouse left the markup view, the highlighter is hidden");
+    return promise.resolve();
   }
 
   function finishUp() {
     inspector = doc = toolbox = null;
     gBrowser.removeCurrentTab();
     finish();
   }
 }
--- a/browser/devtools/inspector/test/browser_inspector_breadcrumbs.js
+++ b/browser/devtools/inspector/test/browser_inspector_breadcrumbs.js
@@ -86,13 +86,13 @@ function test()
 
     let checkedButton = container.querySelector("button[checked]");
     let labelId = checkedButton.querySelector(".breadcrumbs-widget-item-id");
     let id = inspector.selection.node.id;
     is(labelId.textContent, "#" + id, "Node " + cursor + ": selection matches");
   }
 
   function finishUp() {
-    doc = nodes = inspector = null;
+    doc = nodes = null;
     gBrowser.removeCurrentTab();
     finish();
   }
 }
--- a/browser/devtools/inspector/test/browser_inspector_bug_650804_search.js
+++ b/browser/devtools/inspector/test/browser_inspector_bug_650804_search.js
@@ -47,18 +47,17 @@ function test()
   ];
 
   gBrowser.selectedTab = gBrowser.addTab();
   gBrowser.selectedBrowser.addEventListener("load", function onload() {
     gBrowser.selectedBrowser.removeEventListener("load", onload, true);
     waitForFocus(setupTest, content);
   }, true);
 
-  content.location = "http://mochi.test:8888/browser/browser/devtools/" +
-                     "inspector/test/browser_inspector_bug_650804_search.html";
+  content.location = "http://mochi.test:8888/browser/browser/devtools/inspector/test/browser_inspector_bug_650804_search.html";
 
   function $(id) {
     if (id == null) return null;
     return content.document.getElementById(id);
   }
 
   function setupTest()
   {
--- a/browser/devtools/inspector/test/browser_inspector_bug_674871.js
+++ b/browser/devtools/inspector/test/browser_inspector_bug_674871.js
@@ -45,54 +45,51 @@ function test()
     iframeNode = doc.querySelector("iframe");
     iframeBodyNode = iframeNode.contentDocument.querySelector("body");
     ok(iframeNode, "we have the iframe node");
     ok(iframeBodyNode, "we have the body node");
     openInspector(aInspector => {
       inspector = aInspector;
       // Make sure the highlighter is shown so we can disable transitions
       inspector.toolbox.highlighter.showBoxModel(getNodeFront(doc.body)).then(() => {
+        getHighlighterOutline().setAttribute("disable-transitions", "true");
         runTests();
       });
     });
   }
 
   function runTests()
   {
     inspector.toolbox.highlighterUtils.startPicker().then(() => {
       moveMouseOver(iframeNode, 1, 1, isTheIframeHighlighted);
     });
   }
 
   function isTheIframeHighlighted()
   {
-    let {p1, p2, p3, p4} = getBoxModelStatus().border.points;
-    let {top, right, bottom, left} = iframeNode.getBoundingClientRect();
-
-    is(top, p1.y, "iframeRect.top === boxModelStatus.p1.y");
-    is(top, p2.y, "iframeRect.top === boxModelStatus.p2.y");
-    is(right, p2.x, "iframeRect.right === boxModelStatus.p2.x");
-    is(right, p3.x, "iframeRect.right === boxModelStatus.p3.x");
-    is(bottom, p3.y, "iframeRect.bottom === boxModelStatus.p3.y");
-    is(bottom, p4.y, "iframeRect.bottom === boxModelStatus.p4.y");
-    is(left, p1.x, "iframeRect.left === boxModelStatus.p1.x");
-    is(left, p4.x, "iframeRect.left === boxModelStatus.p4.x");
+    let outlineRect = getHighlighterOutlineRect();
+    let iframeRect = iframeNode.getBoundingClientRect();
+    for (let dim of ["width", "height", "top", "left"]) {
+      is(Math.floor(outlineRect[dim]), Math.floor(iframeRect[dim]),
+         "Outline dimension is correct " + outlineRect[dim]);
+    }
 
     iframeNode.style.marginBottom = doc.defaultView.innerHeight + "px";
     doc.defaultView.scrollBy(0, 40);
 
     moveMouseOver(iframeNode, 40, 40, isTheIframeContentHighlighted);
   }
 
   function isTheIframeContentHighlighted()
   {
     is(getHighlitNode(), iframeBodyNode, "highlighter shows the right node");
 
-    let outlineRect = getSimpleBorderRect();
-    is(outlineRect.height, 200, "highlighter height");
+    // 184 == 200 + 11(border) + 13(padding) - 40(scroll)
+    let outlineRect = getHighlighterOutlineRect();
+    is(outlineRect.height, 184, "highlighter height");
 
     inspector.toolbox.highlighterUtils.stopPicker().then(() => {
       let target = TargetFactory.forTab(gBrowser.selectedTab);
       gDevTools.closeToolbox(target);
       finishUp();
     });
   }
 
--- a/browser/devtools/inspector/test/browser_inspector_bug_699308_iframe_navigation.js
+++ b/browser/devtools/inspector/test/browser_inspector_bug_699308_iframe_navigation.js
@@ -13,44 +13,49 @@ function test() {
       runInspectorTests();
     });
   }
 
   function showHighlighter(cb) {
     inspector.toolbox.highlighterUtils.startPicker().then(() => {
       EventUtils.synthesizeMouse(content.document.body, 1, 1,
         {type: "mousemove"}, content);
-      inspector.toolbox.once("highlighter-ready", cb);
+      inspector.toolbox.once("picker-node-hovered", () => {
+        executeSoon(() => {
+          getHighlighterOutline().setAttribute("disable-transitions", "true");
+          cb();
+        });
+      });
     });
   }
 
   function runInspectorTests() {
     iframe = content.document.querySelector("iframe");
     ok(iframe, "found the iframe element");
 
     showHighlighter(() => {
       ok(isHighlighting(), "Inspector is highlighting");
 
       iframe.addEventListener("load", onIframeLoad, false);
-      executeSoon(() => {
+
+      executeSoon(function() {
         iframe.contentWindow.location = "javascript:location.reload()";
       });
     });
   }
 
   function onIframeLoad() {
     if (++iframeLoads != 2) {
       executeSoon(function() {
         iframe.contentWindow.location = "javascript:location.reload()";
       });
       return;
     }
 
     iframe.removeEventListener("load", onIframeLoad, false);
-    info("Finished reloading iframe and inspector updated");
 
     ok(isHighlighting(), "Inspector is highlighting after iframe nav");
 
     checksAfterLoads = true;
 
     finishTest();
   }
 
@@ -68,12 +73,11 @@ function test() {
   waitForExplicitFinish();
 
   gBrowser.selectedTab = gBrowser.addTab();
   gBrowser.selectedBrowser.addEventListener("load", function onBrowserLoad() {
     gBrowser.selectedBrowser.removeEventListener("load", onBrowserLoad, true);
     waitForFocus(startTest, content);
   }, true);
 
-  content.location = "data:text/html;charset=utf-8," +
-                     "<p>bug 699308 - test iframe navigation</p>" +
-                     "<iframe src='data:text/html;charset=utf-8,hello world'></iframe>";
+  content.location = "data:text/html,<p>bug 699308 - test iframe navigation" +
+    "<iframe src='data:text/html,hello world'></iframe>";
 }
--- a/browser/devtools/inspector/test/browser_inspector_bug_958456_highlight_comments.js
+++ b/browser/devtools/inspector/test/browser_inspector_bug_958456_highlight_comments.js
@@ -72,16 +72,17 @@ function finishTest() {
   finish();
 }
 
 function prepareHighlighter() {
   // Make sure the highlighter doesn't have transitions enabled
   let deferred = promise.defer();
   inspector.selection.setNode(doc.querySelector("p"), null);
   inspector.once("inspector-updated", () => {
+    getHighlighterOutline().setAttribute("disable-transitions", "true");
     deferred.resolve();
   });
   return deferred.promise;
 }
 
 function hoverContainer(container) {
   let deferred = promise.defer();
   EventUtils.synthesizeMouse(container.tagLine, 2, 2, {type: "mousemove"},
--- a/browser/devtools/inspector/test/browser_inspector_changes.js
+++ b/browser/devtools/inspector/test/browser_inspector_changes.js
@@ -145,10 +145,10 @@ function test() {
   waitForExplicitFinish();
   gBrowser.selectedTab = gBrowser.addTab();
   gBrowser.selectedBrowser.addEventListener("load", function() {
     gBrowser.selectedBrowser.removeEventListener("load", arguments.callee, true);
     doc = content.document;
     waitForFocus(createDocument, content);
   }, true);
 
-  content.location = "data:text/html;charset=utf-8,browser_inspector_changes.js";
+  content.location = "data:text/html,basic tests for inspector";
 }
--- a/browser/devtools/inspector/test/browser_inspector_highlighter.js
+++ b/browser/devtools/inspector/test/browser_inspector_highlighter.js
@@ -46,65 +46,71 @@ function createDocument() {
   doc.body.appendChild(div);
   doc.body.appendChild(div2);
   doc.body.appendChild(div3);
 
   openInspector(aInspector => {
     inspector = aInspector;
     inspector.selection.setNode(div, null);
     inspector.once("inspector-updated", () => {
+      getHighlighterOutline().setAttribute("disable-transitions", "true");
       inspector.toolbox.highlighterUtils.startPicker().then(testMouseOverH1Highlights);
     });
   });
 }
 
 function testMouseOverH1Highlights() {
-  inspector.toolbox.once("highlighter-ready", () => {
+  inspector.toolbox.once("picker-node-hovered", () => {
     ok(isHighlighting(), "Highlighter is shown");
     is(getHighlitNode(), h1, "Highlighter's outline correspond to the selected node");
-    testBoxModelDimensions();
+    testOutlineDimensions();
   });
 
   EventUtils.synthesizeMouse(h1, 2, 2, {type: "mousemove"}, content);
 }
 
-function testBoxModelDimensions() {
+function testOutlineDimensions() {
   let h1Dims = h1.getBoundingClientRect();
-  let h1Width = Math.ceil(h1Dims.width);
-  let h1Height = Math.ceil(h1Dims.height);
+  let h1Width = h1Dims.width;
+  let h1Height = h1Dims.height;
 
-  let outlineDims = getSimpleBorderRect();
-  let outlineWidth = Math.ceil(outlineDims.width);
-  let outlineHeight = Math.ceil(outlineDims.height);
+  let outlineDims = getHighlighterOutlineRect();
+  let outlineWidth = outlineDims.width;
+  let outlineHeight = outlineDims.height;
 
   // Disabled due to bug 716245
   is(outlineWidth, h1Width, "outline width matches dimensions of element (no zoom)");
   is(outlineHeight, h1Height, "outline height matches dimensions of element (no zoom)");
 
   // zoom the page by a factor of 2
   let contentViewer = gBrowser.selectedBrowser.docShell.contentViewer
                              .QueryInterface(Ci.nsIMarkupDocumentViewer);
   contentViewer.fullZoom = 2;
 
-  // simulate the zoomed dimensions of the div element
-  let h1Dims = h1.getBoundingClientRect();
-  // There seems to be some very minor differences in the floats, so let's
-  // floor the values
-  let h1Width = Math.floor(h1Dims.width * contentViewer.fullZoom);
-  let h1Height = Math.floor(h1Dims.height * contentViewer.fullZoom);
+  // We wait at least 500ms to make sure the highlighter is not "mutting" the
+  // resize event
+
+  window.setTimeout(function() {
+    // simulate the zoomed dimensions of the div element
+    let h1Dims = h1.getBoundingClientRect();
+    // There seems to be some very minor differences in the floats, so let's
+    // floor the values
+    let h1Width = Math.floor(h1Dims.width * contentViewer.fullZoom);
+    let h1Height = Math.floor(h1Dims.height * contentViewer.fullZoom);
 
-  let outlineDims = getSimpleBorderRect();
-  let outlineWidth = Math.floor(outlineDims.width);
-  let outlineHeight = Math.floor(outlineDims.height);
+    let outlineDims = getHighlighterOutlineRect();
+    let outlineWidth = Math.floor(outlineDims.width);
+    let outlineHeight = Math.floor(outlineDims.height);
 
-  is(outlineWidth, h1Width, "outline width matches dimensions of element (zoomed)");
+    // Disabled due to bug 716245
+    is(outlineWidth, h1Width, "outline width matches dimensions of element (zoomed)");
+    is(outlineHeight, h1Height, "outline height matches dimensions of element (zoomed)");
 
-  is(outlineHeight, h1Height, "outline height matches dimensions of element (zoomed)");
-
-  executeSoon(finishUp);
+    executeSoon(finishUp);
+  }, 500);
 }
 
 function finishUp() {
   inspector.toolbox.highlighterUtils.stopPicker().then(() => {
     doc = h1 = inspector = null;
     let target = TargetFactory.forTab(gBrowser.selectedTab);
     gDevTools.closeToolbox(target);
     gBrowser.removeCurrentTab();
@@ -116,10 +122,10 @@ function test() {
   waitForExplicitFinish();
   gBrowser.selectedTab = gBrowser.addTab();
   gBrowser.selectedBrowser.addEventListener("load", function() {
     gBrowser.selectedBrowser.removeEventListener("load", arguments.callee, true);
     doc = content.document;
     waitForFocus(createDocument, content);
   }, true);
 
-  content.location = "data:text/html;charset=utf-8,browser_inspector_highlighter.js";
+  content.location = "data:text/html,basic tests for inspector";
 }
--- a/browser/devtools/inspector/test/browser_inspector_iframeTest.js
+++ b/browser/devtools/inspector/test/browser_inspector_iframeTest.js
@@ -26,54 +26,54 @@ function createDocument() {
     iframe2 = iframe1.contentDocument.createElement('iframe');
 
     iframe2.addEventListener('load', function () {
       iframe2.removeEventListener("load", arguments.callee, false);
 
       div2 = iframe2.contentDocument.createElement('div');
       div2.textContent = 'nested div';
       iframe2.contentDocument.body.appendChild(div2);
-
       // Open the inspector, start the picker mode, and start the tests
       openInspector(aInspector => {
         inspector = aInspector;
-        inspector.once("inspector-updated", () => {
-          inspector.toolbox.highlighterUtils.startPicker().then(runTests);
-        });
+        inspector.toolbox.highlighterUtils.startPicker().then(runTests);
       });
     }, false);
 
     iframe2.src = 'data:text/html,nested iframe';
     iframe1.contentDocument.body.appendChild(iframe2);
   }, false);
 
   iframe1.src = 'data:text/html,little iframe';
   doc.body.appendChild(iframe1);
 }
 
 function moveMouseOver(aElement, cb) {
-  inspector.toolbox.once("picker-node-hovered", cb);
+  inspector.toolbox.once("picker-node-hovered", () => {
+    executeSoon(cb);
+  });
   EventUtils.synthesizeMouseAtCenter(aElement, {type: "mousemove"},
     aElement.ownerDocument.defaultView);
 }
 
 function runTests() {
   testDiv1Highlighter();
 }
 
 function testDiv1Highlighter() {
   moveMouseOver(div1, () => {
-    is(getHighlitNode(), div1, "highlighter matches selection of div1");
+    getHighlighterOutline().setAttribute("disable-transitions", "true");
+    is(getHighlitNode(), div1, "highlighter matches selection");
     testDiv2Highlighter();
   });
 }
 
 function testDiv2Highlighter() {
   moveMouseOver(div2, () => {
-    is(getHighlitNode(), div2, "highlighter matches selection of div2");
+    is(getHighlitNode(), div2, "highlighter matches selection");
     selectRoot();
   });
 }
 
 function selectRoot() {
   // Select the root document element to clear the breadcrumbs.
   inspector.selection.setNode(doc.documentElement, null);
   inspector.once("inspector-updated", selectIframe);
--- a/browser/devtools/inspector/test/browser_inspector_initialization.js
+++ b/browser/devtools/inspector/test/browser_inspector_initialization.js
@@ -132,10 +132,10 @@ function test()
   waitForExplicitFinish();
   gBrowser.selectedTab = gBrowser.addTab();
   gBrowser.selectedBrowser.addEventListener("load", function() {
     gBrowser.selectedBrowser.removeEventListener("load", arguments.callee, true);
     doc = content.document;
     waitForFocus(createDocument, content);
   }, true);
 
-  content.location = "data:text/html;charset=utf-8,browser_inspector_initialization.js";
+  content.location = "data:text/html,basic tests for inspector";
 }
--- a/browser/devtools/inspector/test/browser_inspector_invalidate.js
+++ b/browser/devtools/inspector/test/browser_inspector_invalidate.js
@@ -8,34 +8,34 @@ function test() {
 
   function createDocument() {
     div = doc.createElement("div");
     div.setAttribute("style", "width: 100px; height: 100px; background:yellow;");
     doc.body.appendChild(div);
 
     openInspector(aInspector => {
       inspector = aInspector;
-      inspector.once("inspector-updated", () => {
-        inspector.toolbox.highlighter.showBoxModel(getNodeFront(div)).then(runTest);
-      });
+      inspector.toolbox.highlighter.showBoxModel(getNodeFront(div)).then(runTest);
     });
   }
 
   function runTest() {
-    let rect = getSimpleBorderRect();
-    is(rect.width, 100, "outline has the right width");
+    let outline = getHighlighterOutline();
+    is(outline.style.width, "100px", "outline has the right width");
 
     div.style.width = "200px";
-    inspector.toolbox.once("highlighter-ready", testRectWidth);
-  }
-
-  function testRectWidth() {
-    let rect = getSimpleBorderRect();
-    is(rect.width, 200, "outline updated");
-    finishUp();
+    function pollTest() {
+      if (outline.style.width == "100px") {
+        setTimeout(pollTest, 10);
+        return;
+      }
+      is(outline.style.width, "200px", "outline updated");
+      finishUp();
+    }
+    setTimeout(pollTest, 10);
   }
 
   function finishUp() {
     inspector.toolbox.highlighter.hideBoxModel().then(() => {
       doc = div = inspector = null;
       gBrowser.removeCurrentTab();
       finish();
     });
@@ -44,10 +44,10 @@ function test() {
   waitForExplicitFinish();
   gBrowser.selectedTab = gBrowser.addTab();
   gBrowser.selectedBrowser.addEventListener("load", function() {
     gBrowser.selectedBrowser.removeEventListener("load", arguments.callee, true);
     doc = content.document;
     waitForFocus(createDocument, content);
   }, true);
 
-  content.location = "data:text/html;charset=utf-8,browser_inspector_invalidate.js";
+  content.location = "data:text/html,basic tests for inspector";
 }
--- a/browser/devtools/inspector/test/browser_inspector_scrolling.js
+++ b/browser/devtools/inspector/test/browser_inspector_scrolling.js
@@ -28,44 +28,44 @@ function createDocument()
   iframe.src = "data:text/html,foo bar";
   doc.body.appendChild(iframe);
 }
 
 function inspectNode(aInspector)
 {
   inspector = aInspector;
 
-  let highlighter = inspector.toolbox.highlighter;
-  highlighter.showBoxModel(getNodeFront(div)).then(performScrollingTest);
+  inspector.once("inspector-updated", performScrollingTest);
+  executeSoon(function() {
+    inspector.selection.setNode(div, "");
+  });
 }
 
 function performScrollingTest()
 {
+  executeSoon(function() {
+    // FIXME: this will fail on retina displays. EventUtils will only scroll
+    // 25px down instead of 50.
+    EventUtils.synthesizeWheel(div, 10, 10,
+      { deltaY: 50.0, deltaMode: WheelEvent.DOM_DELTA_PIXEL },
+      iframe.contentWindow);
+  });
+
   gBrowser.selectedBrowser.addEventListener("scroll", function() {
     gBrowser.selectedBrowser.removeEventListener("scroll", arguments.callee,
       false);
-    let isRetina = devicePixelRatio === 2;
-    is(iframe.contentDocument.body.scrollTop,
-      isRetina ? 25 : 50, "inspected iframe scrolled");
 
-    finishUp();
-  }, false);
+    is(iframe.contentDocument.body.scrollTop, 50, "inspected iframe scrolled");
 
-  EventUtils.synthesizeWheel(div, 10, 10,
-    { deltaY: 50.0, deltaMode: WheelEvent.DOM_DELTA_PIXEL },
-    iframe.contentWindow);
-}
-
-function finishUp()
-{
-  inspector = div = iframe = doc = null;
-  let target = TargetFactory.forTab(gBrowser.selectedTab);
-  gDevTools.closeToolbox(target);
-  gBrowser.removeCurrentTab();
-  finish();
+    inspector = div = iframe = doc = null;
+    let target = TargetFactory.forTab(gBrowser.selectedTab);
+    gDevTools.closeToolbox(target);
+    gBrowser.removeCurrentTab();
+    finish();
+  }, false);
 }
 
 function test()
 {
   waitForExplicitFinish();
   gBrowser.selectedTab = gBrowser.addTab();
   gBrowser.selectedBrowser.addEventListener("load", function() {
     gBrowser.selectedBrowser.removeEventListener("load", arguments.callee, true);
--- a/browser/devtools/inspector/test/browser_inspector_sidebarstate.js
+++ b/browser/devtools/inspector/test/browser_inspector_sidebarstate.js
@@ -20,29 +20,28 @@ function inspectorRuleViewOpened()
 {
   is(inspector.sidebar.getCurrentTabID(), "ruleview", "Rule View is selected by default");
 
   // Select the computed view and turn off the inspector.
   inspector.sidebar.select("computedview");
 
   gDevTools.once("toolbox-destroyed", inspectorClosed);
   let target = TargetFactory.forTab(gBrowser.selectedTab);
-  gDevTools.closeToolbox(target);
+  gDevTools.getToolbox(target).destroy();
 }
 
 function inspectorClosed()
 {
   openInspector(function(panel) {
     inspector = panel;
-
     if (inspector.sidebar.getCurrentTabID()) {
-      info("Default sidebar already selected.")
+      // Default sidebar already selected.
       testNewDefaultTab();
     } else {
-      info("Default sidebar still to be selected, adding select listener.");
+      // Default sidebar still to be selected.
       inspector.sidebar.once("select", testNewDefaultTab);
     }
   });
 }
 
 function testNewDefaultTab()
 {
   is(inspector.sidebar.getCurrentTabID(), "computedview", "Computed view is selected by default.");
@@ -63,10 +62,10 @@ function test()
   waitForExplicitFinish();
   gBrowser.selectedTab = gBrowser.addTab();
   gBrowser.selectedBrowser.addEventListener("load", function() {
     gBrowser.selectedBrowser.removeEventListener("load", arguments.callee, true);
     doc = content.document;
     waitForFocus(createDocument, content);
   }, true);
 
-  content.location = "data:text/html;charset=utf-8,browser_inspector_sidebarstate.js";
+  content.location = "data:text/html,basic tests for inspector";
 }
--- a/browser/devtools/inspector/test/browser_inspector_tree_height.js
+++ b/browser/devtools/inspector/test/browser_inspector_tree_height.js
@@ -101,11 +101,11 @@ function test()
   waitForExplicitFinish();
   gBrowser.selectedTab = gBrowser.addTab();
   gBrowser.selectedBrowser.addEventListener("load", function() {
     gBrowser.selectedBrowser.removeEventListener("load", arguments.callee, true);
     doc = content.document;
     waitForFocus(createDocument, content);
   }, true);
 
-  content.location = "data:text/html;charset=utf-8,browser_inspector_tree_height.js";
+  content.location = "data:text/html,basic tests for inspector";
 }
 
--- a/browser/devtools/inspector/test/head.js
+++ b/browser/devtools/inspector/test/head.js
@@ -22,28 +22,22 @@ let TargetFactory = devtools.TargetFacto
 
 Components.utils.import("resource://gre/modules/devtools/Console.jsm", tempScope);
 let console = tempScope.console;
 
 // Import the GCLI test helper
 let testDir = gTestPath.substr(0, gTestPath.lastIndexOf("/"));
 Services.scriptloader.loadSubScript(testDir + "../../../commandline/test/helpers.js", this);
 
-gDevTools.testing = true;
 SimpleTest.registerCleanupFunction(() => {
-  gDevTools.testing = false;
-});
-
-SimpleTest.registerCleanupFunction(() => {
-  console.error("Here we are\n");
+  console.error("Here we are\n")
   let {DebuggerServer} = Cu.import("resource://gre/modules/devtools/dbg-server.jsm", {});
   console.error("DebuggerServer open connections: " + Object.getOwnPropertyNames(DebuggerServer._connections).length);
 
   Services.prefs.clearUserPref("devtools.dump.emit");
-  Services.prefs.clearUserPref("devtools.inspector.activeSidebar");
 });
 
 function openInspector(callback)
 {
   let target = TargetFactory.forTab(gBrowser.selectedTab);
   gDevTools.showToolbox(target, "inspector").then(function(toolbox) {
     callback(toolbox.getCurrentPanel(), toolbox);
   }).then(null, console.error);
@@ -61,128 +55,73 @@ function getNodeFront(node)
   return inspector.walker.frontForRawNode(node);
 }
 
 function getHighlighter()
 {
   return gBrowser.selectedBrowser.parentNode.querySelector(".highlighter-container");
 }
 
-function getSimpleBorderRect() {
-  let {p1, p2, p3, p4} = getBoxModelStatus().border.points;
-
-  return {
-    top: p1.y,
-    left: p1.x,
-    width: p2.x - p1.x,
-    height: p4.y - p1.y
-  };
-}
-
-function getBoxModelRoot() {
-  let highlighter = getHighlighter();
-  return highlighter.querySelector(".box-model-root");
+function getHighlighterOutline()
+{
+  let h = getHighlighter();
+  if (h) {
+    return h.querySelector(".highlighter-outline");
+  }
 }
 
-function getBoxModelStatus() {
-  let root = getBoxModelRoot();
-  let inspector = getActiveInspector();
-
-  return {
-    visible: !root.hasAttribute("hidden"),
-    currentNode: inspector.walker.currentNode,
-    margin: {
-      points: getPointsForRegion("margin"),
-      visible: isRegionHidden("margin")
-    },
-    border: {
-      points: getPointsForRegion("border"),
-      visible: isRegionHidden("border")
-    },
-    padding: {
-      points: getPointsForRegion("padding"),
-      visible: isRegionHidden("padding")
-    },
-    content: {
-      points: getPointsForRegion("content"),
-      visible: isRegionHidden("content")
-    },
-    guides: {
-      top: getGuideStatus("top"),
-      right: getGuideStatus("right"),
-      bottom: getGuideStatus("bottom"),
-      left: getGuideStatus("left")
-    }
-  };
-}
-
-function getGuideStatus(location) {
-  let root = getBoxModelRoot();
-  let guide = root.querySelector(".box-model-guide-" + location);
+function getHighlighterOutlineRect() {
+  let helper = new LayoutHelpers(window.content);
+  let outline = getHighlighterOutline();
 
-  return {
-    visible: !guide.hasAttribute("hidden"),
-    x1: guide.getAttribute("x1"),
-    y1: guide.getAttribute("y1"),
-    x2: guide.getAttribute("x2"),
-    y2: guide.getAttribute("y2")
-  };
-}
-
-function getPointsForRegion(region) {
-  let root = getBoxModelRoot();
-  let box = root.querySelector(".box-model-" + region);
-  let points = box.getAttribute("points").split(/[, ]/);
+  if (outline) {
+    let browserOffsetRect = helper.getDirtyRect(gBrowser.selectedBrowser);
+    let outlineRect = helper.getDirtyRect(outline);
+    outlineRect.top -= browserOffsetRect.top;
+    outlineRect.left -= browserOffsetRect.left;
 
-  // We multiply each value by 1 to cast it into a number
-  return {
-    p1: {
-      x: parseFloat(points[0]),
-      y: parseFloat(points[1])
-    },
-    p2: {
-      x: parseFloat(points[2]),
-      y: parseFloat(points[3])
-    },
-    p3: {
-      x: parseFloat(points[4]),
-      y: parseFloat(points[5])
-    },
-    p4: {
-      x: parseFloat(points[6]),
-      y: parseFloat(points[7])
-    }
-  };
-}
-
-function isRegionHidden(region) {
-  let root = getBoxModelRoot();
-  let box = root.querySelector(".box-model-" + region);
-
-  return !box.hasAttribute("hidden");
+    return outlineRect;
+  }
 }
 
 function isHighlighting()
 {
-  let root = getBoxModelRoot();
-  return !root.hasAttribute("hidden");
+  let outline = getHighlighterOutline();
+  return outline && !outline.hasAttribute("hidden");
 }
 
 function getHighlitNode()
 {
   if (isHighlighting()) {
     let helper = new LayoutHelpers(window.content);
-    let points = getBoxModelStatus().content.points;
-    let x = (points.p1.x + points.p2.x + points.p3.x + points.p4.x) / 4;
-    let y = (points.p1.y + points.p2.y + points.p3.y + points.p4.y) / 4;
+    let outlineRect = getHighlighterOutlineRect();
+
+    let a = {
+      x: outlineRect.left,
+      y: outlineRect.top
+    };
 
+    let b = {
+      x: a.x + outlineRect.width,
+      y: a.y + outlineRect.height
+    };
+
+    let {x, y} = getMidPoint(a, b);
     return helper.getElementFromPoint(window.content.document, x, y);
   }
 }
 
+function getMidPoint(aPointA, aPointB)
+{
+  let pointC = {};
+  pointC.x = (aPointB.x - aPointA.x) / 2 + aPointA.x;
+  pointC.y = (aPointB.y - aPointA.y) / 2 + aPointA.y;
+  return pointC;
+}
+
 function computedView()
 {
   let sidebar = getActiveInspector().sidebar;
   let iframe = sidebar.tabbox.querySelector(".iframe-computedview");
   return iframe.contentWindow.computedView;
 }
 
 function computedViewTree()
--- a/browser/devtools/layoutview/test/browser_layoutview.js
+++ b/browser/devtools/layoutview/test/browser_layoutview.js
@@ -2,21 +2,16 @@
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 let {devtools} = Cu.import("resource://gre/modules/devtools/Loader.jsm", {});
 let TargetFactory = devtools.TargetFactory;
 
 function test() {
   waitForExplicitFinish();
 
-  gDevTools.testing = true;
-  SimpleTest.registerCleanupFunction(() => {
-    gDevTools.testing = false;
-  });
-
   Services.prefs.setBoolPref("devtools.inspector.sidebarOpen", true);
 
   let doc;
   let node;
   let view;
   let inspector;
 
   // Expected values:
--- a/browser/devtools/layoutview/view.css
+++ b/browser/devtools/layoutview/view.css
@@ -49,33 +49,33 @@ body {
   body {
     position: absolute;
     width: 320px;
     left: -160px;
     margin-left: 50%;
   }
 }
 
-#content,
-#borders {
-  border-width: 1px;
+
+#margins {
+  padding: 28px;
 }
 
 #content {
-  height: 25px;
+  height: 20px;
+  border-width: 1px;
 }
 
-#margins,
 #padding {
-  border-style: solid;
   border-width: 25px;
 }
 
 #borders {
-  padding: 25px;
+  border-width: 2px;
+  box-shadow: 0 0 16px black;
 }
 
 #main > p {
   position: absolute;
   pointer-events: none;
 }
 
 #main > p {
@@ -84,94 +84,98 @@ body {
 }
 
 #main > p > span {
   vertical-align: middle;
   pointer-events: auto;
   cursor: default;
 }
 
-.top,
-.bottom {
+.border.top {
+  left: 0; top: 23px;
+  width: 98px;
+}
+
+.border.bottom {
+  right: 0; bottom: 22px;
+  width: 98px;
+  top: auto;
+}
+
+.border.left {
+  top: 42px; left: 0;
+  width: 56px;
+}
+
+.border.right{
+  bottom: 42px; right: 0;
+  width: 56px;
+  top: auto;
+}
+
+.top, .bottom {
   width: calc(100% - 2px);
   text-align: center;
 }
 
-.padding.top {
-  top: 55px;
-}
-
-.padding.bottom {
-  bottom: 57px;
-}
-
-.border.top {
-  top: 30px;
-}
-
-.border.bottom {
-  bottom: 31px;
-}
-
 .margin.top {
-  top: 5px;
+  top: 8px;
 }
 
 .margin.bottom {
   bottom: 6px;
 }
 
+.padding.top {
+  top: 35px;
+}
+
+.padding.bottom {
+  bottom: 35px;
+}
+
 .size,
 .margin.left,
 .margin.right,
-.border.left,
-.border.right,
 .padding.left,
 .padding.right {
-  top: 22px;
+  top: 0;
   line-height: 132px;
 }
 
 .size {
   width: calc(100% - 2px);
 }
 
 .margin.right,
-.margin.left,
-.border.left,
-.border.right,
+.margin.left {
+  width: 28px;
+}
+
 .padding.right,
 .padding.left {
   width: 25px;
 }
 
-.padding.left {
-  left: 52px;
-}
-
-.padding.right {
-  right: 51px;
-}
-
-.border.left {
-  left: 26px;
-}
-
-.border.right {
-  right: 26px;
-}
-
 .margin.right {
   right: 0;
 }
 
 .margin.left {
   left: 0;
 }
 
+.padding.left {
+  left: 30px;
+}
+
+.padding.right {
+  right: 30px;
+}
+
 .tooltip {
   position: absolute;
   bottom: 0;
   right: 2px;
   pointer-events: none;
 }
 
 body.dim > #header > #element-position,
--- a/browser/devtools/layoutview/view.js
+++ b/browser/devtools/layoutview/view.js
@@ -234,51 +234,22 @@ LayoutView.prototype = {
       }
 
       this.inspector.emit("layoutview-updated");
       return null;
     });
 
     this._lastRequest = lastRequest;
     return this._lastRequest;
-  },
-
-  showBoxModel: function(options={}) {
-    let toolbox = this.inspector.toolbox;
-    let nodeFront = this.inspector.selection.nodeFront;
-
-    toolbox.highlighterUtils.highlightNodeFront(nodeFront, options);
-  },
-
-  hideBoxModel: function() {
-    let toolbox = this.inspector.toolbox;
-
-    toolbox.highlighterUtils.unhighlight();
-  },
-};
+  }
+}
 
 let elts;
 let tooltip;
 
-let onmouseover = function(e) {
-  let region = e.target.getAttribute("data-box");
-
-  tooltip.textContent = e.target.getAttribute("tooltip");
-  this.layoutview.showBoxModel({region: region});
-
-  return false;
-}.bind(window);
-
-let onmouseout = function(e) {
-  tooltip.textContent = "";
-  this.layoutview.hideBoxModel();
-
-  return false;
-}.bind(window);
-
 window.setPanel = function(panel) {
   this.layoutview = new LayoutView(panel, window);
 
   // Tooltip mechanism
   elts = document.querySelectorAll("*[tooltip]");
   tooltip = document.querySelector(".tooltip");
   for (let i = 0; i < elts.length; i++) {
     let elt = elts[i];
@@ -300,8 +271,16 @@ window.onunload = function() {
   if (elts) {
     for (let i = 0; i < elts.length; i++) {
       let elt = elts[i];
       elt.removeEventListener("mouseover", onmouseover, true);
       elt.removeEventListener("mouseout", onmouseout, true);
     }
   }
 };
+
+function onmouseover(e) {
+  tooltip.textContent = e.target.getAttribute("tooltip");
+}
+
+function onmouseout(e) {
+  tooltip.textContent = "";
+}
\ No newline at end of file
--- a/browser/devtools/layoutview/view.xhtml
+++ b/browser/devtools/layoutview/view.xhtml
@@ -25,40 +25,40 @@
   <body class="theme-body devtools-monospace">
 
     <p id="header">
       <span id="element-size"></span><span id="element-position"></span>
     </p>
 
     <div id="main">
 
-      <div id="margins" data-box="margin" tooltip="&margins.tooltip;">
-        <div id="borders" data-box="border" tooltip="&borders.tooltip;">
-          <div id="padding" data-box="padding" tooltip="&padding.tooltip;">
-            <div id="content" data-box="content" tooltip="&content.tooltip;">
+      <div id="margins" tooltip="&margins.tooltip;">
+        <div id="borders" tooltip="&borders.tooltip;">
+          <div id="padding" tooltip="&padding.tooltip;">
+            <div id="content" tooltip="&content.tooltip;">
             </div>
           </div>
         </div>
       </div>
 
-      <p class="border top"><span data-box="border" tooltip="border-top"></span></p>
-      <p class="border right"><span data-box="border" tooltip="border-right"></span></p>
-      <p class="border bottom"><span data-box="border" tooltip="border-bottom"></span></p>
-      <p class="border left"><span data-box="border" tooltip="border-left"></span></p>
+      <p class="border top"><span tooltip="border-top"></span></p>
+      <p class="border right"><span tooltip="border-right"></span></p>
+      <p class="border bottom"><span tooltip="border-bottom"></span></p>
+      <p class="border left"><span tooltip="border-left"></span></p>
 
-      <p class="margin top"><span data-box="margin" tooltip="margin-top"></span></p>
-      <p class="margin right"><span data-box="margin" tooltip="margin-right"></span></p>
-      <p class="margin bottom"><span data-box="margin" tooltip="margin-bottom"></span></p>
-      <p class="margin left"><span data-box="margin" tooltip="margin-left"></span></p>
+      <p class="margin top"><span tooltip="margin-top"></span></p>
+      <p class="margin right"><span tooltip="margin-right"></span></p>
+      <p class="margin bottom"><span tooltip="margin-bottom"></span></p>
+      <p class="margin left"><span tooltip="margin-left"></span></p>
 
-      <p class="padding top"><span data-box="padding" tooltip="padding-top"></span></p>
-      <p class="padding right"><span data-box="padding" tooltip="padding-right"></span></p>
-      <p class="padding bottom"><span data-box="padding" tooltip="padding-bottom"></span></p>
-      <p class="padding left"><span data-box="padding" tooltip="padding-left"></span></p>
+      <p class="padding top"><span tooltip="padding-top"></span></p>
+      <p class="padding right"><span tooltip="padding-right"></span></p>
+      <p class="padding bottom"><span tooltip="padding-bottom"></span></p>
+      <p class="padding left"><span tooltip="padding-left"></span></p>
 
-      <p class="size"><span data-box="content" tooltip="&content.tooltip;"></span></p>
+      <p class="size"><span tooltip="&content.tooltip;"></span></p>
 
       <span class="tooltip"></span>
 
     </div>
 
   </body>
 </html>
--- a/browser/devtools/markupview/markup-view.js
+++ b/browser/devtools/markupview/markup-view.js
@@ -160,29 +160,29 @@ MarkupView.prototype = {
       }
       this._containers.get(nodeFront).hovered = true;
 
       this._hoveredNode = nodeFront;
     }
   },
 
   _onMouseLeave: function() {
-    this._hideBoxModel(true);
+    this._hideBoxModel();
     if (this._hoveredNode) {
       this._containers.get(this._hoveredNode).hovered = false;
     }
     this._hoveredNode = null;
   },
 
   _showBoxModel: function(nodeFront, options={}) {
     this._inspector.toolbox.highlighterUtils.highlightNodeFront(nodeFront, options);
   },
 
-  _hideBoxModel: function(forceHide) {
-    this._inspector.toolbox.highlighterUtils.unhighlight(forceHide);
+  _hideBoxModel: function() {
+    this._inspector.toolbox.highlighterUtils.unhighlight();
   },
 
   _briefBoxModelTimer: null,
   _brieflyShowBoxModel: function(nodeFront, options) {
     let win = this._frame.contentWindow;
 
     if (this._briefBoxModelTimer) {
       win.clearTimeout(this._briefBoxModelTimer);
@@ -1540,16 +1540,18 @@ MarkupContainer.prototype = {
       if (firstChild.container) {
         firstChild.container.destroy();
       }
       this.children.removeChild(firstChild);
     }
 
     // Remove event listeners
     this.elt.removeEventListener("dblclick", this._onToggle, false);
+    this.elt.removeEventListener("mouseover", this._onMouseOver, false);
+    this.elt.removeEventListener("mouseout", this._onMouseOut, false);
     this.elt.removeEventListener("mousedown", this._onMouseDown, false);
     this.expander.removeEventListener("click", this._onToggle, false);
 
     // Destroy my editor
     this.editor.destroy();
   }
 };
 
--- a/browser/devtools/markupview/test/browser_inspector_markup_968316_highlight_node_after_mouseleave_mousemove.js
+++ b/browser/devtools/markupview/test/browser_inspector_markup_968316_highlight_node_after_mouseleave_mousemove.js
@@ -10,17 +10,17 @@ function test() {
   waitForExplicitFinish();
 
   gBrowser.selectedTab = gBrowser.addTab();
   gBrowser.selectedBrowser.addEventListener("load", function onload(evt) {
     gBrowser.selectedBrowser.removeEventListener("load", onload, true);
     waitForFocus(startTests, content);
   }, true);
 
-  content.location = "data:text/html;charset=utf-8,<p>Select me!</p>";
+  content.location = "data:text/html,<p>Select me!</p>";
 }
 
 function startTests(aInspector, aToolbox) {
   let p = content.document.querySelector("p");
   Task.spawn(function() {
     info("opening the inspector tool");
     let {inspector, toolbox} = yield openInspector();
 
--- a/browser/devtools/markupview/test/browser_inspector_markup_968316_highlit_node_on_hover_then_select.js
+++ b/browser/devtools/markupview/test/browser_inspector_markup_968316_highlit_node_on_hover_then_select.js
@@ -10,17 +10,17 @@ function test() {
   waitForExplicitFinish();
 
   gBrowser.selectedTab = gBrowser.addTab();
   gBrowser.selectedBrowser.addEventListener("load", function onload(evt) {
     gBrowser.selectedBrowser.removeEventListener("load", onload, true);
     waitForFocus(startTests, content);
   }, true);
 
-  content.location = "data:text/html;charset=utf-8,<p>It's going to be legen....</p>";
+  content.location = "data:text/html,<p>It's going to be legen....</p>";
 }
 
 function startTests(aInspector, aToolbox) {
   let p = content.document.querySelector("p");
   Task.spawn(function() {
     info("opening the inspector tool");
     let {inspector, toolbox} = yield openInspector();
 
--- a/browser/devtools/markupview/test/browser_inspector_markup_navigation.js
+++ b/browser/devtools/markupview/test/browser_inspector_markup_navigation.js
@@ -120,17 +120,17 @@ function test() {
       case "pagedown":
         EventUtils.synthesizeKey("VK_PAGE_DOWN", {});
         break;
       case "home":
         EventUtils.synthesizeKey("VK_HOME", {});
         break;
     }
 
-    inspector.markup._waitForChildren().then(() => executeSoon(() => {
+    inspector.markup._waitForChildren().then(() => executeSoon(function BIMNT_newNode() {
       let node = inspector.selection.node;
 
       if (className == "*comment*") {
         is(node.nodeType, Node.COMMENT_NODE, "[" + cursor + "] should be a comment after moving " + key);
       } else if (className == "*text*") {
         is(node.nodeType, Node.TEXT_NODE, "[" + cursor + "] should be text after moving " + key);
       } else if (className == "*doctype*") {
         is(node.nodeType, Node.DOCUMENT_TYPE_NODE, "[" + cursor + "] should be doctype after moving " + key);
--- a/browser/devtools/markupview/test/head.js
+++ b/browser/devtools/markupview/test/head.js
@@ -7,21 +7,16 @@ const Cu = Components.utils;
 let {devtools} = Cu.import("resource://gre/modules/devtools/Loader.jsm", {});
 let TargetFactory = devtools.TargetFactory;
 let {console} = Cu.import("resource://gre/modules/devtools/Console.jsm", {});
 let promise = devtools.require("sdk/core/promise");
 let {getInplaceEditorForSpan: inplaceEditor} = devtools.require("devtools/shared/inplace-editor");
 
 //Services.prefs.setBoolPref("devtools.dump.emit", true);
 
-gDevTools.testing = true;
-SimpleTest.registerCleanupFunction(() => {
-  gDevTools.testing = false;
-});
-
 // Clear preferences that may be set during the course of tests.
 function clearUserPrefs() {
   Services.prefs.clearUserPref("devtools.inspector.htmlPanelOpen");
   Services.prefs.clearUserPref("devtools.inspector.sidebarOpen");
   Services.prefs.clearUserPref("devtools.inspector.activeSidebar");
   Services.prefs.clearUserPref("devtools.dump.emit");
 }
 
@@ -120,17 +115,17 @@ function selectNode(nodeOrSelector, insp
  * @param {InspectorPanel} inspector The instance of InspectorPanel currently loaded in the toolbox
  * @return a promise that resolves when the container is hovered and the higlighter
  * is shown on the corresponding node
  */
 function hoverContainer(nodeOrSelector, inspector) {
   info("Hovering over the markup-container for node " + nodeOrSelector);
   let highlit = inspector.toolbox.once("node-highlight");
   let container = getContainerForRawNode(inspector.markup, getNode(nodeOrSelector));
-  EventUtils.synthesizeMouseAtCenter(container.tagLine, {type: "mousemove"},
+  EventUtils.synthesizeMouse(container.tagLine, 2, 2, {type: "mousemove"},
     inspector.markup.doc.defaultView);
   return highlit;
 }
 
 /**
  * Simulate a click on the markup-container (a line in the markup-view)
  * that corresponds to the node or selector passed.
  * @param {String|DOMNode} nodeOrSelector
@@ -148,34 +143,33 @@ function clickContainer(nodeOrSelector, 
   return updated;
 }
 
 /**
  * Checks if the highlighter is visible currently
  * @return {Boolean}
  */
 function isHighlighterVisible() {
-  let highlighter = gBrowser.selectedBrowser.parentNode
-                            .querySelector(".highlighter-container .box-model-root");
-  return highlighter && !highlighter.hasAttribute("hidden");
+  let outline = gBrowser.selectedBrowser.parentNode.querySelector(".highlighter-container .highlighter-outline");
+  return outline && !outline.hasAttribute("hidden");
 }
 
 /**
  * Simulate the mouse leaving the markup-view area
  * @param {InspectorPanel} inspector The instance of InspectorPanel currently loaded in the toolbox
  * @return a promise when done
  */
 function mouseLeaveMarkupView(inspector) {
   info("Leaving the markup-view area");
   let def = promise.defer();
 
   // Find another element to mouseover over in order to leave the markup-view
   let btn = inspector.toolbox.doc.querySelector(".toolbox-dock-button");
 
-  EventUtils.synthesizeMouseAtCenter(btn, {type: "mousemove"},
+  EventUtils.synthesizeMouse(btn, 2, 2, {type: "mousemove"},
     inspector.toolbox.doc.defaultView);
   executeSoon(def.resolve);
 
   return def.promise;
 }
 
 /**
  * Focus a given editable element, enter edit mode, set value, and commit
--- a/browser/devtools/netmonitor/test/head.js
+++ b/browser/devtools/netmonitor/test/head.js
@@ -38,34 +38,28 @@ const STATISTICS_URL = EXAMPLE_URL + "ht
 const SIMPLE_SJS = EXAMPLE_URL + "sjs_simple-test-server.sjs";
 const CONTENT_TYPE_SJS = EXAMPLE_URL + "sjs_content-type-test-server.sjs";
 const STATUS_CODES_SJS = EXAMPLE_URL + "sjs_status-codes-test-server.sjs";
 const SORTING_SJS = EXAMPLE_URL + "sjs_sorting-test-server.sjs";
 
 const TEST_IMAGE = EXAMPLE_URL + "test-image.png";
 const TEST_IMAGE_DATA_URI = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAAK/INwWK6QAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAHWSURBVHjaYvz//z8DJQAggJiQOe/fv2fv7Oz8rays/N+VkfG/iYnJfyD/1+rVq7ffu3dPFpsBAAHEAHIBCJ85c8bN2Nj4vwsDw/8zQLwKiO8CcRoQu0DxqlWrdsHUwzBAAIGJmTNnPgYa9j8UqhFElwPxf2MIDeIrKSn9FwSJoRkAEEAM0DD4DzMAyPi/G+QKY4hh5WAXGf8PDQ0FGwJ22d27CjADAAIIrLmjo+MXA9R2kAHvGBA2wwx6B8W7od6CeQcggKCmCEL8bgwxYCbUIGTDVkHDBia+CuotgACCueD3TDQN75D4xmAvCoK9ARMHBzAw0AECiBHkAlC0Mdy7x9ABNA3obAZXIAa6iKEcGlMVQHwWyjYuL2d4v2cPg8vZswx7gHyAAAK7AOif7SAbOqCmn4Ha3AHFsIDtgPq/vLz8P4MSkJ2W9h8ggBjevXvHDo4FQUQg/kdypqCg4H8lUIACnQ/SOBMYI8bAsAJFPcj1AAEEjwVQqLpAbXmH5BJjqI0gi9DTAAgDBBCcAVLkgmQ7yKCZxpCQxqUZhAECCJ4XgMl493ug21ZD+aDAXH0WLM4A9MZPXJkJIIAwTAR5pQMalaCABQUULttBGCCAGCnNzgABBgAMJ5THwGvJLAAAAABJRU5ErkJggg==";
 
-gDevTools.testing = true;
-SimpleTest.registerCleanupFunction(() => {
-  gDevTools.testing = false;
-});
-
 // All tests are asynchronous.
 waitForExplicitFinish();
 
 // Enable logging for all the relevant tests.
 const gEnableLogging = Services.prefs.getBoolPref("devtools.debugger.log");
 Services.prefs.setBoolPref("devtools.debugger.log", true);
 
 // Always reset some prefs to their original values after the test finishes.
 const gDefaultFilters = Services.prefs.getCharPref("devtools.netmonitor.filters");
 
 registerCleanupFunction(() => {
   info("finish() was called, cleaning up...");
-
   Services.prefs.setBoolPref("devtools.debugger.log", gEnableLogging);
   Services.prefs.setCharPref("devtools.netmonitor.filters", gDefaultFilters);
 });
 
 function addTab(aUrl, aWindow) {
   info("Adding tab: " + aUrl);
 
   let deferred = promise.defer();
--- a/browser/devtools/profiler/test/head.js
+++ b/browser/devtools/profiler/test/head.js
@@ -18,21 +18,16 @@ let TargetFactory = temp.devtools.Target
 
 Cu.import("resource://gre/modules/devtools/dbg-server.jsm", temp);
 let DebuggerServer = temp.DebuggerServer;
 
 // Import the GCLI test helper
 let testDir = gTestPath.substr(0, gTestPath.lastIndexOf("/"));
 Services.scriptloader.loadSubScript(testDir + "../../../commandline/test/helpers.js", this);
 
-gDevTools.testing = true;
-SimpleTest.registerCleanupFunction(() => {
-  gDevTools.testing = false;
-});
-
 registerCleanupFunction(function () {
   helpers = null;
   Services.prefs.clearUserPref(PROFILER_ENABLED);
   Services.prefs.clearUserPref(REMOTE_ENABLED);
   Services.prefs.clearUserPref(SHOW_PLATFORM_DATA);
   DebuggerServer.destroy();
 
   // These tests use a lot of memory due to GL contexts, so force a GC to help
--- a/browser/devtools/responsivedesign/test/head.js
+++ b/browser/devtools/responsivedesign/test/head.js
@@ -5,21 +5,16 @@
 
 let {devtools} = Cu.import("resource:///modules/devtools/gDevTools.jsm", {});
 let TargetFactory = devtools.TargetFactory;
 
 // Import the GCLI test helper
 let testDir = gTestPath.substr(0, gTestPath.lastIndexOf("/"));
 Services.scriptloader.loadSubScript(testDir + "../../../commandline/test/helpers.js", this);
 
-gDevTools.testing = true;
-SimpleTest.registerCleanupFunction(() => {
-  gDevTools.testing = false;
-});
-
 function openInspector(callback)
 {
   let target = TargetFactory.forTab(gBrowser.selectedTab);
   gDevTools.showToolbox(target, "inspector").then(function(toolbox) {
     callback(toolbox.getCurrentPanel());
   });
 }
 
--- a/browser/devtools/scratchpad/test/browser_scratchpad_revert_to_saved.js
+++ b/browser/devtools/scratchpad/test/browser_scratchpad_revert_to_saved.js
@@ -85,17 +85,18 @@ function testAfterSecondSave() {
 function testAfterSecondRevert() {
   // Check if the file's text got reverted
   is(gScratchpad.getText(), gFileContent + "\nalert(foo.toSource());",
      "The text reverted back to the changed saved text.");
   // The revert menu should be disabled again.
   ok(menu.hasAttribute("disabled"),
      "Revert menu entry is disabled after reverting to changed saved state.");
   gFile.remove(false);
-  gFile = gScratchpad = menu = null;
+  gFile = null;
+  gScratchpad = null;
   finish();
 }
 
 function createAndLoadTemporaryFile()
 {
   // Create a temporary file.
   gFile = FileUtils.getFile("TmpD", [gFileName]);
   gFile.createUnique(Ci.nsIFile.NORMAL_FILE_TYPE, 0666);
--- a/browser/devtools/scratchpad/test/head.js
+++ b/browser/devtools/scratchpad/test/head.js
@@ -5,21 +5,16 @@
 "use strict";
 
 const {NetUtil} = Cu.import("resource://gre/modules/NetUtil.jsm", {});
 const {FileUtils} = Cu.import("resource://gre/modules/FileUtils.jsm", {});
 const {Promise: promise} = Cu.import("resource://gre/modules/Promise.jsm", {});
 
 let gScratchpadWindow; // Reference to the Scratchpad chrome window object
 
-gDevTools.testing = true;
-SimpleTest.registerCleanupFunction(() => {
-  gDevTools.testing = false;
-});
-
 /**
  * Open a Scratchpad window.
  *
  * @param function aReadyCallback
  *        Optional. The function you want invoked when the Scratchpad instance
  *        is ready.
  * @param object aOptions
  *        Optional. Options for opening the scratchpad:
--- a/browser/devtools/shared/test/head.js
+++ b/browser/devtools/shared/test/head.js
@@ -1,21 +1,16 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 let {devtools} = Cu.import("resource://gre/modules/devtools/Loader.jsm", {});
 let TargetFactory = devtools.TargetFactory;
 let {console} = Cu.import("resource://gre/modules/devtools/Console.jsm", {});
 
-gDevTools.testing = true;
-SimpleTest.registerCleanupFunction(() => {
-  gDevTools.testing = false;
-});
-
 /**
  * Open a new tab at a URL and call a callback on load
  */
 function addTab(aURL, aCallback)
 {
   waitForExplicitFinish();
 
   gBrowser.selectedTab = gBrowser.addTab();
--- a/browser/devtools/sourceeditor/editor.js
+++ b/browser/devtools/sourceeditor/editor.js
@@ -27,17 +27,18 @@ const L10N = Services.strings.createBund
 // CM_STYLES, CM_SCRIPTS and CM_IFRAME represent the HTML,
 // JavaScript and CSS that is injected into an iframe in
 // order to initialize a CodeMirror instance.
 
 const CM_STYLES   = [
   "chrome://browser/skin/devtools/common.css",
   "chrome://browser/content/devtools/codemirror/codemirror.css",
   "chrome://browser/content/devtools/codemirror/dialog.css",
-  "chrome://browser/content/devtools/codemirror/mozilla.css"
+  "chrome://browser/content/devtools/codemirror/mozilla.css",
+  "chrome://browser/content/devtools/codemirror/foldgutter.css"
 ];
 
 const CM_SCRIPTS  = [
   "chrome://browser/content/devtools/theme-switching.js",
   "chrome://browser/content/devtools/codemirror/codemirror.js",
   "chrome://browser/content/devtools/codemirror/dialog.js",
   "chrome://browser/content/devtools/codemirror/searchcursor.js",
   "chrome://browser/content/devtools/codemirror/search.js",
--- a/browser/devtools/sourceeditor/test/head.js
+++ b/browser/devtools/sourceeditor/test/head.js
@@ -3,21 +3,16 @@
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 "use strict";
 
 const { devtools } = Cu.import("resource://gre/modules/devtools/Loader.jsm", {});
 const { require } = devtools;
 const Editor  = require("devtools/sourceeditor/editor");
 
-gDevTools.testing = true;
-SimpleTest.registerCleanupFunction(() => {
-  gDevTools.testing = false;
-});
-
 function setup(cb) {
   const opt = "chrome,titlebar,toolbar,centerscreen,resizable,dialog=no";
   const url = "data:text/xml;charset=UTF-8,<?xml version='1.0'?>" +
     "<?xml-stylesheet href='chrome://global/skin/global.css'?>" +
     "<window xmlns='http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul'" +
     " title='Editor' width='600' height='500'><box flex='1'/></window>";
 
   let win = Services.ww.openWindow(null, url, "_blank", opt, null);
--- a/browser/devtools/styleeditor/test/head.js
+++ b/browser/devtools/styleeditor/test/head.js
@@ -18,21 +18,16 @@ let gPanelWindow;
 let cache = Cc["@mozilla.org/netwerk/cache-storage-service;1"]
               .getService(Ci.nsICacheStorageService);
 
 
 // Import the GCLI test helper
 let testDir = gTestPath.substr(0, gTestPath.lastIndexOf("/"));
 Services.scriptloader.loadSubScript(testDir + "../../../commandline/test/helpers.js", this);
 
-gDevTools.testing = true;
-SimpleTest.registerCleanupFunction(() => {
-  gDevTools.testing = false;
-});
-
 function cleanup()
 {
   gPanelWindow = null;
   while (gBrowser.tabs.length > 1) {
     gBrowser.removeCurrentTab();
   }
 }
 
--- a/browser/devtools/styleinspector/style-inspector.js
+++ b/browser/devtools/styleinspector/style-inspector.js
@@ -130,17 +130,17 @@ RuleViewTool.prototype = {
 
     this.view.destroy();
 
     delete this.outerIFrame;
     delete this.view;
     delete this.doc;
     delete this.inspector;
   }
-};
+}
 
 function ComputedViewTool(aInspector, aWindow, aIFrame)
 {
   this.inspector = aInspector;
   this.window = aWindow;
   this.document = aWindow.document;
   this.outerIFrame = aIFrame;
   this.view = new ComputedView.CssHtmlTree(this, aInspector.pageStyle);
--- a/browser/devtools/styleinspector/test/browser_ruleview_inherit.js
+++ b/browser/devtools/styleinspector/test/browser_ruleview_inherit.js
@@ -107,10 +107,10 @@ function test()
   waitForExplicitFinish();
   gBrowser.selectedTab = gBrowser.addTab();
   gBrowser.selectedBrowser.addEventListener("load", function(evt) {
     gBrowser.selectedBrowser.removeEventListener(evt.type, arguments.callee, true);
     doc = content.document;
     waitForFocus(() => openRuleView(simpleInherit), content);
   }, true);
 
-  content.location = "data:text/html;charset=utf-8,browser_inspector_changes.js";
+  content.location = "data:text/html,basic style inspector tests";
 }
--- a/browser/devtools/styleinspector/test/browser_ruleview_manipulation.js
+++ b/browser/devtools/styleinspector/test/browser_ruleview_manipulation.js
@@ -78,10 +78,10 @@ function test()
   waitForExplicitFinish();
   gBrowser.selectedTab = gBrowser.addTab();
   gBrowser.selectedBrowser.addEventListener("load", function(evt) {
     gBrowser.selectedBrowser.removeEventListener(evt.type, arguments.callee, true);
     doc = content.document;
     waitForFocus(() => openRuleView(simpleOverride), content);
   }, true);
 
-  content.location = "data:text/html;charset=utf-8,browser_ruleview_manipulation.js";
+  content.location = "data:text/html,basic style inspector tests";
 }
--- a/browser/devtools/styleinspector/test/browser_ruleview_override.js
+++ b/browser/devtools/styleinspector/test/browser_ruleview_override.js
@@ -173,10 +173,10 @@ function test()
   waitForExplicitFinish();
   gBrowser.selectedTab = gBrowser.addTab();
   gBrowser.selectedBrowser.addEventListener("load", function(evt) {
     gBrowser.selectedBrowser.removeEventListener(evt.type, arguments.callee, true);
     doc = content.document;
     waitForFocus(() => openRuleView(simpleOverride), content);
   }, true);
 
-  content.location = "data:text/html;charset=utf-8,browser_ruleview_override.js";
+  content.location = "data:text/html,basic style inspector tests";
 }
--- a/browser/devtools/styleinspector/test/browser_ruleview_ui.js
+++ b/browser/devtools/styleinspector/test/browser_ruleview_ui.js
@@ -243,10 +243,10 @@ function test()
   waitForExplicitFinish();
   gBrowser.selectedTab = gBrowser.addTab();
   gBrowser.selectedBrowser.addEventListener("load", function(evt) {
     gBrowser.selectedBrowser.removeEventListener(evt.type, arguments.callee, true);
     doc = content.document;
     waitForFocus(() => openRuleView(startTest), content);
   }, true);
 
-  content.location = "data:text/html;charset=utf-8,browser_ruleview_ui.js";
+  content.location = "data:text/html,basic style inspector tests";
 }
--- a/browser/devtools/styleinspector/test/browser_ruleview_update.js
+++ b/browser/devtools/styleinspector/test/browser_ruleview_update.js
@@ -184,10 +184,10 @@ function test()
   waitForExplicitFinish();
   gBrowser.selectedTab = gBrowser.addTab();
   gBrowser.selectedBrowser.addEventListener("load", function(evt) {
     gBrowser.selectedBrowser.removeEventListener(evt.type, arguments.callee, true);
     doc = content.document;
     waitForFocus(() => openRuleView(startTest), content);
   }, true);
 
-  content.location = "data:text/html;charset=utf-8,browser_ruleview_update.js";
+  content.location = "data:text/html,basic style inspector tests";
 }
--- a/browser/devtools/styleinspector/test/head.js
+++ b/browser/devtools/styleinspector/test/head.js
@@ -4,42 +4,37 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 const TEST_BASE_HTTP = "http://example.com/browser/browser/devtools/styleinspector/test/";
 const TEST_BASE_HTTPS = "https://example.com/browser/browser/devtools/styleinspector/test/";
 
 //Services.prefs.setBoolPref("devtools.dump.emit", true);
 Services.prefs.setBoolPref("devtools.debugger.log", true);
 
+SimpleTest.registerCleanupFunction(() => {
+  Services.prefs.clearUserPref("devtools.debugger.log");
+  Services.prefs.clearUserPref("devtools.dump.emit");
+});
+
 let tempScope = {};
 
 Cu.import("resource:///modules/devtools/gDevTools.jsm", tempScope);
 let ConsoleUtils = tempScope.ConsoleUtils;
 let gDevTools = tempScope.gDevTools;
 
 Cu.import("resource://gre/modules/devtools/Loader.jsm", tempScope);
 let devtools = tempScope.devtools;
 
 let TargetFactory = devtools.TargetFactory;
 let {CssHtmlTree} = devtools.require("devtools/styleinspector/computed-view");
 let {CssRuleView, _ElementStyle} = devtools.require("devtools/styleinspector/rule-view");
 let {CssLogic, CssSelector} = devtools.require("devtools/styleinspector/css-logic");
 
 let promise = devtools.require("sdk/core/promise");
 
-gDevTools.testing = true;
-SimpleTest.registerCleanupFunction(() => {
-  gDevTools.testing = false;
-});
-
-SimpleTest.registerCleanupFunction(() => {
-  Services.prefs.clearUserPref("devtools.debugger.log");
-  Services.prefs.clearUserPref("devtools.dump.emit");
-});
-
 let {
   editableField,
   getInplaceEditorForSpan: inplaceEditor
 } = devtools.require("devtools/shared/inplace-editor");
 Components.utils.import("resource://gre/modules/devtools/Console.jsm", tempScope);
 let console = tempScope.console;
 
 let browser, hudId, hud, hudBox, filterBox, outputNode, cs;
--- a/browser/devtools/tilt/test/head.js
+++ b/browser/devtools/tilt/test/head.js
@@ -51,20 +51,16 @@ const DESTROYED = Tilt.NOTIFICATIONS.DES
 const SHOWN = Tilt.NOTIFICATIONS.SHOWN;
 const HIDDEN = Tilt.NOTIFICATIONS.HIDDEN;
 const HIGHLIGHTING = Tilt.NOTIFICATIONS.HIGHLIGHTING;
 const UNHIGHLIGHTING = Tilt.NOTIFICATIONS.UNHIGHLIGHTING;
 const NODE_REMOVED = Tilt.NOTIFICATIONS.NODE_REMOVED;
 
 const TILT_ENABLED = Services.prefs.getBoolPref("devtools.tilt.enabled");
 
-gDevTools.testing = true;
-SimpleTest.registerCleanupFunction(() => {
-  gDevTools.testing = false;
-});
 
 function isTiltEnabled() {
   info("Apparently, Tilt is" + (TILT_ENABLED ? "" : " not") + " enabled.");
   return TILT_ENABLED;
 }
 
 function isWebGLSupported() {
   let supported = !TiltGL.isWebGLForceEnabled() &&
--- a/browser/devtools/webconsole/test/browser_console_variables_view_highlighter.js
+++ b/browser/devtools/webconsole/test/browser_console_variables_view_highlighter.js
@@ -61,17 +61,17 @@ function onNodeListVviewFetched(aEvent, 
           clickOnDomNodeVariableAndAssertInspectorSelected(index);
         });
       });
 
       // Rather than trying to emulate a mouseenter event, let's call the
       // variable's highlightDomNode and see if it has the desired effect
       prop.highlightDomNode();
     } else {
-      finishUp();
+      finishTest();
     }
   }
 
   function clickOnDomNodeVariableAndAssertInspectorSelected(index) {
     let prop = props[index][1];
 
     // Make sure the inspector is initialized so we can listen to its events
     gToolbox.initInspector().then(() => {
@@ -84,14 +84,8 @@ function onNodeListVviewFetched(aEvent, 
           hoverOverDomNodeVariableAndAssertHighlighter(index + 1);
         });
       });
     });
   }
 
   hoverOverDomNodeVariableAndAssertHighlighter(0);
 }
-
-function finishUp() {
-  gWebConsole = gJSTerm = gVariablesView = gToolbox = null;
-
-  finishTest();
-}
--- a/browser/devtools/webconsole/test/browser_webconsole_autocomplete_in_debugger_stackframe.js
+++ b/browser/devtools/webconsole/test/browser_webconsole_autocomplete_in_debugger_stackframe.js
@@ -209,17 +209,17 @@ function testCompletion(hud) {
   input.setSelectionRange(11, 11);
   jsterm.complete(jsterm.COMPLETE_HINT_ONLY, testNext);
   yield undefined;
 
   newItems = popup.getItems();
   is(newItems.length, 0, "no items for foo2Obj[0]");
 
   testDriver = null;
-  executeSoon(finishUp);
+  executeSoon(finishTest);
   yield undefined;
 }
 
 function debuggerOpened(aResult)
 {
   let debuggerWin = aResult.panelWin;
   let debuggerController = debuggerWin.DebuggerController;
   let thread = debuggerController.activeThread;
@@ -232,13 +232,8 @@ function debuggerOpened(aResult)
   });
 }
 
 function onFramesAdded()
 {
   info("onFramesAdded, openConsole() now");
   executeSoon(() => openConsole(null, testNext));
 }
-
-function finishUp() {
-  testDriver = gStackframes = null;
-  finishTest();
-}
--- a/browser/devtools/webconsole/test/browser_webconsole_bug_585991_autocomplete_keys.js
+++ b/browser/devtools/webconsole/test/browser_webconsole_bug_585991_autocomplete_keys.js
@@ -327,15 +327,10 @@ function popupHideAfterCompletionInText(
 
   ok(!popup.isOpen, "popup is not open");
   is(inputNode.value, "dump(window.testBug873250b)",
      "completion was successful after VK_TAB");
   is(inputNode.selectionStart, 26, "cursor location is correct");
   is(inputNode.selectionStart, inputNode.selectionEnd, "cursor location (confirmed)");
   ok(!completeNode.value, "completeNode is empty");
 
-  finishUp();
-}
-
-function finishUp() {
-  HUD = popup = jsterm = inputNode = completeNode = null;
   finishTest();
 }
--- a/browser/devtools/webconsole/test/browser_webconsole_bug_651501_document_body_autocomplete.js
+++ b/browser/devtools/webconsole/test/browser_webconsole_bug_651501_document_body_autocomplete.js
@@ -79,15 +79,10 @@ function testPropertyPanel()
     EventUtils.synthesizeMouse(anchor, 2, 2, {}, gHUD.iframeWindow);
   });
 }
 
 function onVariablesViewReady(aEvent, aView)
 {
   findVariableViewProperties(aView, [
     { name: "body", value: "<body>" },
-  ], { webconsole: gHUD }).then(finishUp);
+  ], { webconsole: gHUD }).then(finishTest);
 }
-
-function finishUp() {
-  gHUD = null;
-  finishTest();
-}
--- a/browser/devtools/webconsole/test/browser_webconsole_output_01.js
+++ b/browser/devtools/webconsole/test/browser_webconsole_output_01.js
@@ -84,15 +84,10 @@ function test() {
     DebuggerServer.LONG_STRING_LENGTH = LONG_STRING_LENGTH;
     DebuggerServer.LONG_STRING_INITIAL_LENGTH = LONG_STRING_INITIAL_LENGTH;
   });
 
   Task.spawn(function*() {
     let {tab} = yield loadTab(TEST_URI);
     let hud = yield openConsole(tab);
     return checkOutputForInputs(hud, inputTests);
-  }).then(finishUp);
+  }).then(finishTest);
 }
-
-function finishUp() {
-  inputTests = null;
-  finishTest();
-}
--- a/browser/devtools/webconsole/test/browser_webconsole_output_03.js
+++ b/browser/devtools/webconsole/test/browser_webconsole_output_03.js
@@ -148,22 +148,17 @@ let inputTests = [
     output: 'class="test1 tezt2"',
     printOutput: "[object Attr]",
     inspectable: true,
     variablesViewLabel: 'class="test1 tezt2"',
   },
 ];
 
 function test() {
+
   addTab(TEST_URI);
   browser.addEventListener("load", function onLoad() {
     browser.removeEventListener("load", onLoad, true);
     openConsole().then((hud) => {
       return checkOutputForInputs(hud, inputTests);
-    }).then(finishUp);
+    }).then(finishTest);
   }, true);
 }
-
-function finishUp() {
-  inputTests = null;
-
-  finishTest();
-}
--- a/browser/devtools/webconsole/test/browser_webconsole_view_source.js
+++ b/browser/devtools/webconsole/test/browser_webconsole_view_source.js
@@ -23,17 +23,17 @@ function testViewSource(hud) {
 
   let button = content.document.querySelector("button");
   ok(button, "we have the button on the page");
 
   expectUncaughtException();
   EventUtils.sendMouseEvent({ type: "click" }, button, content);
 
   openDebugger().then(({panelWin: { DebuggerView }}) => {
-    info("debugger opened");
+    info("debugger openeed");
     Sources = DebuggerView.Sources;
     openConsole(null, (hud) => {
       info("console opened again");
 
       waitForMessages({
         webconsole: hud,
         messages: [{
           text: "fooBazBaz is not defined",
@@ -66,19 +66,22 @@ let observer = {
   observe: function(aSubject, aTopic, aData) {
     if (aTopic != "domwindowopened") {
       return;
     }
 
     ok(true, "the view source window was opened in response to clicking " +
        "the location node");
 
-    aSubject.close();
-    ok(containsValueInvoked, "custom containsValue() was invoked");
-    Sources.containsValue = containsValue;
-    Sources = containsValue = null;
-    finishTest();
+    // executeSoon() is necessary to avoid crashing Firefox. See bug 611543.
+    executeSoon(function() {
+      aSubject.close();
+      ok(containsValueInvoked, "custom containsValue() was invoked");
+      Sources.containsValue = containsValue;
+      Sources = containsValue = null;
+      finishTest();
+    });
   }
 };
 
 registerCleanupFunction(function() {
   Services.ww.unregisterNotification(observer);
 });
--- a/browser/devtools/webconsole/test/head.js
+++ b/browser/devtools/webconsole/test/head.js
@@ -35,21 +35,16 @@ const SEVERITY_LOG = 3;
 const GROUP_INDENT = 12;
 
 // The default indent in pixels, applied even without any groups.
 const GROUP_INDENT_DEFAULT = 6;
 
 const WEBCONSOLE_STRINGS_URI = "chrome://browser/locale/devtools/webconsole.properties";
 let WCU_l10n = new WebConsoleUtils.l10n(WEBCONSOLE_STRINGS_URI);
 
-gDevTools.testing = true;
-SimpleTest.registerCleanupFunction(() => {
-  gDevTools.testing = false;
-});
-
 function log(aMsg)
 {
   dump("*** WebConsoleTest: " + aMsg + "\n");
 }
 
 function pprint(aObj)
 {
   for (let prop in aObj) {
@@ -298,17 +293,17 @@ function dumpMessageElement(aMessage)
                 "severity", aMessage.severity,
                 "repeats", repeats,
                 "clipboardText", aMessage.clipboardText,
                 "text", text);
 }
 
 function finishTest()
 {
-  browser = hudId = hud = filterBox = outputNode = cs = hudBox = null;
+  browser = hudId = hud = filterBox = outputNode = cs = null;
 
   dumpConsoles();
 
   let browserConsole = HUDService.getBrowserConsole();
   if (browserConsole) {
     if (browserConsole.jsterm) {
       browserConsole.jsterm.clearOutput(true);
     }
--- a/browser/themes/linux/browser.css
+++ b/browser/themes/linux/browser.css
@@ -3,17 +3,16 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 %endif
 
 @import url("chrome://global/skin/");
 
 @namespace url("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul");
 @namespace html url("http://www.w3.org/1999/xhtml");
-@namespace svg url("http://www.w3.org/2000/svg");
 
 %include ../shared/browser.inc
 %include linuxShared.inc
 %filter substitution
 
 %define forwardTransitionLength 150ms
 %define conditionalForwardWithUrlbar window:not([chromehidden~="toolbar"]) #urlbar-container
 %define conditionalForwardWithUrlbarWidth 27
--- a/browser/themes/linux/devtools/layoutview.css
+++ b/browser/themes/linux/devtools/layoutview.css
@@ -6,45 +6,41 @@
   background-image: url(layout-background-grid.png);
 }
 
 .theme-light .theme-body {
   background-image: url(layout-background-grid.png), radial-gradient(circle at 50% 70%, hsl(210,53%,45%) 0%, hsl(210,54%,33%) 100%);
 }
 
 .theme-body {
-  color: hsl(210,53%,45%) !important;
+  color: hsl(210,100%,85%) !important;
   box-sizing: border-box;
 }
 
 #main {
-  background-color: white;
   border-color: hsla(210,100%,85%,0.7);
   border-style: dotted;
 }
 
-#content {
-  background-color: #80d4ff;
-  border-color: hsl(210,100%,85%);
-  border-style: dotted;
+#main > .border {
+  color: hsl(210,53%,45%);
 }
 
-#padding,
-#margins {
-  border-color: hsla(210,100%,85%,0.2);
-  outline: dotted 1px hsl(210,100%,85%);
+.border > span {
+  background-color: hsl(210,100%,85%);
+  border-radius: 2px;
+  padding: 0 4px;
+}
+
+#content {
+  border-color: hsla(210,100%,85%,0.7);
+  border-style: dotted 
 }
 
 #padding {
-  background-color: #66cc52;
+  border-color: hsla(210,100%,85%,0.2);
+  border-style: solid;
 }
 
 #borders {
-  background-color: #ffe431;
-  border-style: dotted;
+  border-style: solid;
   border-color: hsl(210,100%,85%);
-  box-shadow: 0 0 8px #000;
 }
-
-#margins {
-  background-color: #d89b28;
-  opacity: 0.6;
-}
--- a/browser/themes/osx/browser.css
+++ b/browser/themes/osx/browser.css
@@ -9,17 +9,16 @@
 %define forwardTransitionLength 150ms
 %define conditionalForwardWithUrlbar window:not([chromehidden~="toolbar"]) #urlbar-container
 %define conditionalForwardWithUrlbarWidth 27
 %define spaceAboveTabbar 9px
 %define toolbarButtonPressed :hover:active:not([disabled="true"]):not([cui-areatype="menu-panel"])
 
 @namespace url("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul");
 @namespace html url("http://www.w3.org/1999/xhtml");
-@namespace svg url("http://www.w3.org/2000/svg");
 
 #urlbar:-moz-lwtheme:not([focused="true"]),
 .searchbar-textbox:-moz-lwtheme:not([focused="true"]) {
   opacity: .9;
 }
 
 #navigator-toolbox::after {
   -moz-box-ordinal-group: 101; /* tabs toolbar is 100 */
--- a/browser/themes/osx/devtools/layoutview.css
+++ b/browser/themes/osx/devtools/layoutview.css
@@ -6,45 +6,41 @@
   background-image: url(layout-background-grid.png);
 }
 
 .theme-light .theme-body {
   background-image: url(layout-background-grid.png), radial-gradient(circle at 50% 70%, hsl(210,53%,45%) 0%, hsl(210,54%,33%) 100%);
 }
 
 .theme-body {
-  color: hsl(210,53%,45%) !important;
+  color: hsl(210,100%,85%) !important;
   box-sizing: border-box;
 }
 
 #main {
-  background-color: white;
   border-color: hsla(210,100%,85%,0.7);
   border-style: dotted;
 }
 
-#content {
-  background-color: #80d4ff;
-  border-color: hsl(210,100%,85%);
-  border-style: dotted;
+#main > .border {
+  color: hsl(210,53%,45%);
 }
 
-#padding,
-#margins {
-  border-color: hsla(210,100%,85%,0.2);
-  outline: dotted 1px hsl(210,100%,85%);
+.border > span {
+  background-color: hsl(210,100%,85%);
+  border-radius: 2px;
+  padding: 0 4px;
+}
+
+#content {
+  border-color: hsla(210,100%,85%,0.7);
+  border-style: dotted 
 }
 
 #padding {
-  background-color: #66cc52;
+  border-color: hsla(210,100%,85%,0.2);
+  border-style: solid;
 }
 
 #borders {
-  background-color: #ffe431;
-  border-style: dotted;
+  border-style: solid;
   border-color: hsl(210,100%,85%);
-  box-shadow: 0 0 8px #000;
 }
-
-#margins {
-  background-color: #d89b28;
-  opacity: 0.6;
-}
--- a/browser/themes/shared/devtools/highlighter.inc.css
+++ b/browser/themes/shared/devtools/highlighter.inc.css
@@ -1,48 +1,20 @@
 %if 0
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 %endif
 
-/* Box model highlighter */
-svg|g.box-model-container {
-  opacity: 0.4;
-}
-
-svg|polygon.box-model-content {
-  fill: #80d4ff;
-}
-
-svg|polygon.box-model-padding {
-  fill: #66cc52;
-}
-
-svg|polygon.box-model-border {
-  fill: #ffe431;
-}
+/* Highlighter */
 
-svg|polygon.box-model-margin {
-  fill: #d89b28;
-}
-
-svg|polygon.box-model-content,
-svg|polygon.box-model-padding,
-svg|polygon.box-model-border,
-svg|polygon.box-model-margin {
-  stroke: none;
-}
-
-svg|line.box-model-guide-top,
-svg|line.box-model-guide-right,
-svg|line.box-model-guide-bottom,
-svg|line.box-model-guide-left {
-  stroke: #08C;
-  stroke-dasharray: 5 3;
+.highlighter-outline {
+  box-shadow: 0 0 0 1px black;
+  outline: 1px dashed white;
+  outline-offset: -1px;
 }
 
 /* Highlighter - Node Infobar */
 
 .highlighter-nodeinfobar {
   color: hsl(216,33%,97%);
   border-radius: 3px;
   background: hsl(214,13%,24%) no-repeat padding-box;
--- a/browser/themes/windows/browser.css
+++ b/browser/themes/windows/browser.css
@@ -1,17 +1,16 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 @import url("chrome://global/skin/");
 
 @namespace url("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul");
 @namespace html url("http://www.w3.org/1999/xhtml");
-@namespace svg url("http://www.w3.org/2000/svg");
 
 %include ../shared/browser.inc
 %include windowsShared.inc
 %filter substitution
 %define toolbarShadowColor hsla(209,67%,12%,0.35)
 %define navbarTextboxCustomBorder border-color: rgba(0,0,0,.32);
 %define forwardTransitionLength 150ms
 %define conditionalForwardWithUrlbar window:not([chromehidden~="toolbar"]) #urlbar-container
--- a/browser/themes/windows/devtools/layoutview.css
+++ b/browser/themes/windows/devtools/layoutview.css
@@ -6,45 +6,41 @@
   background-image: url(layout-background-grid.png);
 }
 
 .theme-light .theme-body {
   background-image: url(layout-background-grid.png), radial-gradient(circle at 50% 70%, hsl(210,53%,45%) 0%, hsl(210,54%,33%) 100%);
 }
 
 .theme-body {
-  color: hsl(210,53%,45%) !important;
+  color: hsl(210,100%,85%) !important;
   box-sizing: border-box;
 }
 
 #main {
-  background-color: white;
   border-color: hsla(210,100%,85%,0.7);
   border-style: dotted;
 }
 
-#content {
-  background-color: #80d4ff;
-  border-color: hsl(210,100%,85%);
-  border-style: dotted;
+#main > .border {
+  color: hsl(210,53%,45%);
 }
 
-#padding,
-#margins {
-  border-color: hsla(210,100%,85%,0.2);
-  outline: dotted 1px hsl(210,100%,85%);
+.border > span {
+  background-color: hsl(210,100%,85%);
+  border-radius: 2px;
+  padding: 0 4px;
+}
+
+#content {
+  border-color: hsla(210,100%,85%,0.7);
+  border-style: dotted 
 }
 
 #padding {
-  background-color: #66cc52;
+  border-color: hsla(210,100%,85%,0.2);
+  border-style: solid;
 }
 
 #borders {
-  background-color: #ffe431;
-  border-style: dotted;
+  border-style: solid;
   border-color: hsl(210,100%,85%);
-  box-shadow: 0 0 8px #000;
 }
-
-#margins {
-  background-color: #d89b28;
-  opacity: 0.6;
-}
--- a/toolkit/devtools/LayoutHelpers.jsm
+++ b/toolkit/devtools/LayoutHelpers.jsm
@@ -19,83 +19,87 @@ this.LayoutHelpers = LayoutHelpers = fun
   this._topDocShell = aTopLevelWindow.QueryInterface(Ci.nsIInterfaceRequestor)
                                      .getInterface(Ci.nsIWebNavigation)
                                      .QueryInterface(Ci.nsIDocShell);
 };
 
 LayoutHelpers.prototype = {
 
   /**
-   * Get box quads adjusted for iframes and zoom level.
+   * Compute the position and the dimensions for the visible portion
+   * of a node, relativalely to the root window.
    *
-   * @param {DOMNode} node
-   *        The node for which we are to get the box model region quads
-   * @param  {String} region
-   *         The box model region to return:
-   *         "content", "padding", "border" or "margin"
+   * @param nsIDOMNode aNode
+   *        a DOM element to be highlighted
    */
-  getAdjustedQuads: function(node, region) {
-    if (!node) {
-      return;
-    }
+  getDirtyRect: function LH_getDirectyRect(aNode) {
+    let frameWin = aNode.ownerDocument.defaultView;
+    let clientRect = aNode.getBoundingClientRect();
+
+    // Go up in the tree of frames to determine the correct rectangle.
+    // clientRect is read-only, we need to be able to change properties.
+    rect = {top: clientRect.top,
+            left: clientRect.left,
+            width: clientRect.width,
+            height: clientRect.height};
+
+    // We iterate through all the parent windows.
+    while (true) {
+
+      // Does the selection overflow on the right of its window?
+      let diffx = frameWin.innerWidth - (rect.left + rect.width);
+      if (diffx < 0) {
+        rect.width += diffx;
+      }
+
+      // Does the selection overflow on the bottom of its window?
+      let diffy = frameWin.innerHeight - (rect.top + rect.height);
+      if (diffy < 0) {
+        rect.height += diffy;
+      }
 
-    let [quads] = node.getBoxQuads({
-      box: region
-    });
+      // Does the selection overflow on the left of its window?
+      if (rect.left < 0) {
+        rect.width += rect.left;
+        rect.left = 0;
+      }
+
+      // Does the selection overflow on the top of its window?
+      if (rect.top < 0) {
+        rect.height += rect.top;
+        rect.top = 0;
+      }
+
+      // Selection has been clipped to fit in its own window.
 
-    if (!quads) {
-      return;
+      // Are we in the top-level window?
+      if (this.isTopLevelWindow(frameWin)) {
+        break;
+      }
+
+      let frameElement = this.getFrameElement(frameWin);
+      if (!frameElement) {
+        break;
+      }
+
+      // We are in an iframe.
+      // We take into account the parent iframe position and its
+      // offset (borders and padding).
+      let frameRect = frameElement.getBoundingClientRect();
+
+      let [offsetTop, offsetLeft] =
+        this.getIframeContentOffset(frameElement);
+
+      rect.top += frameRect.top + offsetTop;
+      rect.left += frameRect.left + offsetLeft;
+
+      frameWin = this.getParentWindow(frameWin);
     }
 
-    let [xOffset, yOffset] = this._getNodeOffsets(node);
-    let scale = this.calculateScale(node);
-
-    return {
-      p1: {
-        w: quads.p1.w * scale,
-        x: quads.p1.x * scale + xOffset,
-        y: quads.p1.y * scale + yOffset,
-        z: quads.p1.z * scale
-      },
-      p2: {
-        w: quads.p2.w * scale,
-        x: quads.p2.x * scale + xOffset,
-        y: quads.p2.y * scale + yOffset,
-        z: quads.p2.z * scale
-      },
-      p3: {
-        w: quads.p3.w * scale,
-        x: quads.p3.x * scale + xOffset,
-        y: quads.p3.y * scale + yOffset,
-        z: quads.p3.z * scale
-      },
-      p4: {
-        w: quads.p4.w * scale,
-        x: quads.p4.x * scale + xOffset,
-        y: quads.p4.y * scale + yOffset,
-        z: quads.p4.z * scale
-      },
-      bounds: {
-        bottom: quads.bounds.bottom * scale + yOffset,
-        height: quads.bounds.height * scale,
-        left: quads.bounds.left * scale + xOffset,
-        right: quads.bounds.right * scale + xOffset,
-        top: quads.bounds.top * scale + yOffset,
-        width: quads.bounds.width * scale,
-        x: quads.bounds.x * scale + xOffset,
-        y: quads.bounds.y * scale + yOffset
-      }
-    };
-  },
-
-  calculateScale: function(node) {
-    let win = node.ownerDocument.defaultView;
-    let winUtils = win.QueryInterface(Ci.nsIInterfaceRequestor)
-                      .getInterface(Ci.nsIDOMWindowUtils);
-    return winUtils.fullZoom;
+    return rect;
   },
 
   /**
    * Compute the absolute position and the dimensions of a node, relativalely
    * to the root window.
    *
    * @param nsIDOMNode aNode
    *        a DOM element to get the bounds for
@@ -103,17 +107,17 @@ LayoutHelpers.prototype = {
    *        the content window holding the node
    */
   getRect: function LH_getRect(aNode, aContentWindow) {
     let frameWin = aNode.ownerDocument.defaultView;
     let clientRect = aNode.getBoundingClientRect();
 
     // Go up in the tree of frames to determine the correct rectangle.
     // clientRect is read-only, we need to be able to change properties.
-    let rect = {top: clientRect.top + aContentWindow.pageYOffset,
+    rect = {top: clientRect.top + aContentWindow.pageYOffset,
             left: clientRect.left + aContentWindow.pageXOffset,
             width: clientRect.width,
             height: clientRect.height};
 
     // We iterate through all the parent windows.
     while (true) {
 
       // Are we in the top-level window?
@@ -170,16 +174,36 @@ LayoutHelpers.prototype = {
 
     let borderTop = parseInt(style.getPropertyValue("border-top-width"));
     let borderLeft = parseInt(style.getPropertyValue("border-left-width"));
 
     return [borderTop + paddingTop, borderLeft + paddingLeft];
   },
 
   /**
+   * Apply the page zoom factor.
+   */
+  getZoomedRect: function LH_getZoomedRect(aWin, aRect) {
+    // get page zoom factor, if any
+    let zoom =
+      aWin.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
+        .getInterface(Components.interfaces.nsIDOMWindowUtils)
+        .fullZoom;
+
+    // adjust rect for zoom scaling
+    let aRectScaled = {};
+    for (let prop in aRect) {
+      aRectScaled[prop] = aRect[prop] * zoom;
+    }
+
+    return aRectScaled;
+  },
+
+
+  /**
    * Find an element from the given coordinates. This method descends through
    * frames to find the element the user clicked inside frames.
    *
    * @param DOMDocument aDocument the document to look into.
    * @param integer aX
    * @param integer aY
    * @returns Node|null the element node found at the given coordinates.
    */
@@ -214,17 +238,18 @@ LayoutHelpers.prototype = {
   /**
    * Scroll the document so that the element "elem" appears in the viewport.
    *
    * @param Element elem the element that needs to appear in the viewport.
    * @param bool centered true if you want it centered, false if you want it to
    * appear on the top of the viewport. It is true by default, and that is
    * usually what you want.
    */
-  scrollIntoViewIfNeeded: function(elem, centered) {
+  scrollIntoViewIfNeeded:
+  function LH_scrollIntoViewIfNeeded(elem, centered) {
     // We want to default to centering the element in the page,
     // so as to keep the context of the element.
     centered = centered === undefined? true: !!centered;
 
     let win = elem.ownerDocument.defaultView;
     let clientRect = elem.getBoundingClientRect();
 
     // The following are always from the {top, bottom, left, right}
@@ -367,143 +392,9 @@ LayoutHelpers.prototype = {
     }
 
     let winUtils = win.
       QueryInterface(Components.interfaces.nsIInterfaceRequestor).
       getInterface(Components.interfaces.nsIDOMWindowUtils);
 
     return winUtils.containerElement;
   },
-
-  /**
-   * Get the x and y offsets for a node taking iframes into account.
-   *
-   * @param {DOMNode} node
-   *        The node for which we are to get the offset
-   */
-  _getNodeOffsets: function(node) {
-    let xOffset = 0;
-    let yOffset = 0;
-    let frameWin = node.ownerDocument.defaultView;
-    let scale = this.calculateScale(node);
-
-    while (true) {
-      // Are we in the top-level window?
-      if (this.isTopLevelWindow(frameWin)) {
-        break;
-      }
-
-      let frameElement = this.getFrameElement(frameWin);
-      if (!frameElement) {
-        break;
-      }
-
-      // We are in an iframe.
-      // We take into account the parent iframe position and its
-      // offset (borders and padding).
-      let frameRect = frameElement.getBoundingClientRect();
-
-      let [offsetTop, offsetLeft] =
-        this.getIframeContentOffset(frameElement);
-
-      xOffset += frameRect.left + offsetLeft;
-      yOffset += frameRect.top + offsetTop;
-
-      frameWin = this.getParentWindow(frameWin);
-    }
-
-    return [xOffset * scale, yOffset * scale];
-  },
-
-
-
-  /********************************************************************
-   * GetBoxQuads POLYFILL START TODO: Remove this when bug 917755 is fixed.
-   ********************************************************************/
-  _getBoxQuadsFromRect: function(rect, node) {
-    let scale = this.calculateScale(node);
-    let [xOffset, yOffset] = this._getNodeOffsets(node);
-
-    let out = {
-      p1: {
-        x: rect.left * scale + xOffset,
-        y: rect.top * scale + yOffset
-      },
-      p2: {
-        x: (rect.left + rect.width) * scale + xOffset,
-        y: rect.top * scale + yOffset
-      },
-      p3: {
-        x: (rect.left + rect.width) * scale + xOffset,
-        y: (rect.top + rect.height) * scale + yOffset
-      },
-      p4: {
-        x: rect.left * scale + xOffset,
-        y: (rect.top + rect.height) * scale + yOffset
-      }
-    };
-
-    out.bounds = {
-      bottom: out.p4.y,
-      height: out.p4.y - out.p1.y,
-      left: out.p1.x,
-      right: out.p2.x,
-      top: out.p1.y,
-      width: out.p2.x - out.p1.x,
-      x: out.p1.x,
-      y: out.p1.y
-    };
-
-    return out;
-  },
-
-  _parseNb: function(distance) {
-    let nb = parseFloat(distance, 10);
-    return isNaN(nb) ? 0 : nb;
-  },
-
-  getAdjustedQuadsPolyfill: function(node, region) {
-    // Get the border-box rect
-    // Note that this is relative to the node's viewport, so before we can use
-    // it, will need to go back up the frames like getRect
-    let borderRect = node.getBoundingClientRect();
-
-    // If the boxType is border, no need to go any further, we're done
-    if (region === "border") {
-      return this._getBoxQuadsFromRect(borderRect, node);
-    }
-
-    // Else, need to get margin/padding/border distances
-    let style = node.ownerDocument.defaultView.getComputedStyle(node);
-    let camel = s => s.substring(0, 1).toUpperCase() + s.substring(1);
-    let distances = {border:{}, padding:{}, margin: {}};
-
-    for (let side of ["top", "right", "bottom", "left"]) {
-      distances.border[side] = this._parseNb(style["border" + camel(side) + "Width"]);
-      distances.padding[side] = this._parseNb(style["padding" + camel(side)]);
-      distances.margin[side] = this._parseNb(style["margin" + camel(side)]);
-    }
-
-    // From the border-box rect, calculate the content-box, padding-box and
-    // margin-box rects
-    function offsetRect(rect, offsetType, dir=1) {
-      return {
-        top: rect.top + (dir * distances[offsetType].top),
-        left: rect.left + (dir * distances[offsetType].left),
-        width: rect.width - (dir * (distances[offsetType].left + distances[offsetType].right)),
-        height: rect.height - (dir * (distances[offsetType].top + distances[offsetType].bottom))
-      };
-    }
-
-    if (region === "margin") {
-      return this._getBoxQuadsFromRect(offsetRect(borderRect, "margin", -1), node);
-    } else if (region === "padding") {
-      return this._getBoxQuadsFromRect(offsetRect(borderRect, "border"), node);
-    } else if (region === "content") {
-      let paddingRect = offsetRect(borderRect, "border");
-      return this._getBoxQuadsFromRect(offsetRect(paddingRect, "padding"), node);
-    }
-  },
-
-  /********************************************************************
-   * GetBoxQuads POLYFILL END
-   ********************************************************************/
 };
--- a/toolkit/devtools/server/actors/highlighter.js
+++ b/toolkit/devtools/server/actors/highlighter.js
@@ -3,66 +3,53 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 const {Cu, Cc, Ci} = require("chrome");
 const protocol = require("devtools/server/protocol");
 const {Arg, Option, method} = protocol;
 const events = require("sdk/event/core");
-const EventEmitter = require("devtools/toolkit/event-emitter");
-const GUIDE_STROKE_WIDTH = 1;
-
 // Make sure the domnode type is known here
 require("devtools/server/actors/inspector");
 
 Cu.import("resource://gre/modules/devtools/LayoutHelpers.jsm");
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource://gre/modules/Services.jsm");
 
 // FIXME: add ":visited" and ":link" after bug 713106 is fixed
 const PSEUDO_CLASSES = [":hover", ":active", ":focus"];
 const HIGHLIGHTED_PSEUDO_CLASS = ":-moz-devtools-highlighted";
 let HELPER_SHEET = ".__fx-devtools-hide-shortcut__ { visibility: hidden !important } ";
 HELPER_SHEET += ":-moz-devtools-highlighted { outline: 2px dashed #F06!important; outline-offset: -2px!important } ";
 const XHTML_NS = "http://www.w3.org/1999/xhtml";
-const SVG_NS = "http://www.w3.org/2000/svg";
 const HIGHLIGHTER_PICKED_TIMER = 1000;
-const INFO_BAR_OFFSET = 5;
 
 /**
  * The HighlighterActor is the server-side entry points for any tool that wishes
  * to highlight elements in the content document.
  *
  * The highlighter can be retrieved via the inspector's getHighlighter method.
  */
 
 /**
  * The HighlighterActor class
  */
 let HighlighterActor = protocol.ActorClass({
   typeName: "highlighter",
 
-  initialize: function(inspector, autohide) {
+  initialize: function(inspector) {
     protocol.Actor.prototype.initialize.call(this, null);
 
-    this._autohide = autohide;
     this._inspector = inspector;
     this._walker = this._inspector.walker;
     this._tabActor = this._inspector.tabActor;
 
-    this._highlighterReady = this._highlighterReady.bind(this);
-    this._highlighterHidden = this._highlighterHidden.bind(this);
-
     if (this._supportsBoxModelHighlighter()) {
-      this._boxModelHighlighter =
-        new BoxModelHighlighter(this._tabActor, this._inspector);
-
-        this._boxModelHighlighter.on("ready", this._highlighterReady);
-        this._boxModelHighlighter.on("hide", this._highlighterHidden);
+      this._boxModelHighlighter = new BoxModelHighlighter(this._tabActor);
     } else {
       this._boxModelHighlighter = new SimpleOutlineHighlighter(this._tabActor);
     }
   },
 
   get conn() this._inspector && this._inspector.conn,
 
   /**
@@ -71,48 +58,45 @@ let HighlighterActor = protocol.ActorCla
    */
   _supportsBoxModelHighlighter: function() {
     return this._tabActor.browser && !!this._tabActor.browser.parentNode;
   },
 
   destroy: function() {
     protocol.Actor.prototype.destroy.call(this);
     if (this._boxModelHighlighter) {
-      this._boxModelHighlighter.off("ready", this._highlighterReady);
-      this._boxModelHighlighter.off("hide", this._highlighterHidden);
       this._boxModelHighlighter.destroy();
       this._boxModelHighlighter = null;
     }
-    this._autohide = null;
     this._inspector = null;
     this._walker = null;
     this._tabActor = null;
   },
 
   /**
    * Display the box model highlighting on a given NodeActor.
    * There is only one instance of the box model highlighter, so calling this
    * method several times won't display several highlighters, it will just move
    * the highlighter instance to these nodes.
    *
    * @param NodeActor The node to be highlighted
    * @param Options See the request part for existing options. Note that not
-   * all options may be supported by all types of highlighters.
+   * all options may be supported by all types of highlighters. The simple
+   * outline highlighter for instance does not scrollIntoView
    */
   showBoxModel: method(function(node, options={}) {
     if (node && this._isNodeValidForHighlighting(node.rawNode)) {
       this._boxModelHighlighter.show(node.rawNode, options);
     } else {
       this._boxModelHighlighter.hide();
     }
   }, {
     request: {
       node: Arg(0, "domnode"),
-      scrollIntoView: Option(1),
-      region: Option(1)
+      scrollIntoView: Option(1)
     }
   }),
 
   _isNodeValidForHighlighting: function(node) {
     // Is it null or dead?
     let isNotDead = node && !Cu.isDeadWrapper(node);
 
     // Is it connected to the document?
@@ -146,37 +130,34 @@ let HighlighterActor = protocol.ActorCla
    * mousemove, and click listeners on the content document to fire
    * events and let connected clients know when nodes are hovered over or
    * clicked.
    *
    * Once a node is picked, events will cease, and listeners will be removed.
    */
   _isPicking: false,
   _hoveredNode: null,
-
   pick: method(function() {
     if (this._isPicking) {
       return null;
     }
     this._isPicking = true;
 
     this._preventContentEvent = event => {
       event.stopPropagation();
       event.preventDefault();
     };
 
     this._onPick = event => {
       this._preventContentEvent(event);
       this._stopPickerListeners();
       this._isPicking = false;
-      if (this._autohide) {
-        this._tabActor.window.setTimeout(() => {
-          this._boxModelHighlighter.hide();
-        }, HIGHLIGHTER_PICKED_TIMER);
-      }
+      this._tabActor.window.setTimeout(() => {
+        this._boxModelHighlighter.hide();
+      }, HIGHLIGHTER_PICKED_TIMER);
       events.emit(this._walker, "picker-node-picked", this._findAndAttachElement(event));
     };
 
     this._onHovered = event => {
       this._preventContentEvent(event);
       let res = this._findAndAttachElement(event);
       if (this._hoveredNode !== res.node) {
         this._boxModelHighlighter.show(res.node.rawNode);
@@ -231,24 +212,16 @@ let HighlighterActor = protocol.ActorCla
     let target = this._getPickerListenerTarget();
     target.removeEventListener("mousemove", this._onHovered, true);
     target.removeEventListener("click", this._onPick, true);
     target.removeEventListener("mousedown", this._preventContentEvent, true);
     target.removeEventListener("mouseup", this._preventContentEvent, true);
     target.removeEventListener("dblclick", this._preventContentEvent, true);
   },
 
-  _highlighterReady: function() {
-    events.emit(this._inspector.walker, "highlighter-ready");
-  },
-
-  _highlighterHidden: function() {
-    events.emit(this._inspector.walker, "highlighter-hide");
-  },
-
   cancelPick: method(function() {
     if (this._isPicking) {
       this._boxModelHighlighter.hide();
       this._stopPickerListeners();
       this._isPicking = false;
       this._hoveredNode = null;
     }
   })
@@ -269,108 +242,69 @@ let HighlighterFront = protocol.FrontCla
  * Usage example:
  *
  * let h = new BoxModelHighlighter(browser);
  * h.show(node);
  * h.hide();
  * h.destroy();
  *
  * Structure:
- * <stack class="highlighter-container">
- *   <svg class="box-model-root" hidden="true">
- *     <g class="box-model-container">
- *       <polygon class="box-model-margin" points="317,122 747,36 747,181 317,267" />
- *       <polygon class="box-model-border" points="317,128 747,42 747,161 317,247" />
- *       <polygon class="box-model-padding" points="323,127 747,42 747,161 323,246" />
- *       <polygon class="box-model-content" points="335,137 735,57 735,152 335,232" />
- *     </g>
- *     <line class="box-model-guide-top" x1="0" y1="592" x2="99999" y2="592" />
- *     <line class="box-model-guide-right" x1="735" y1="0" x2="735" y2="99999" />
- *     <line class="box-model-guide-bottom" x1="0" y1="612" x2="99999" y2="612" />
- *     <line class="box-model-guide-left" x1="334" y1="0" x2="334" y2="99999" />
- *   </svg>
- *   <box class="highlighter-nodeinfobar-container">
- *     <box class="highlighter-nodeinfobar-positioner" position="top" />
- *       <box class="highlighter-nodeinfobar-arrow highlighter-nodeinfobar-arrow-top" />
- *       <hbox class="highlighter-nodeinfobar">
- *         <hbox class="highlighter-nodeinfobar-text" align="center" flex="1">
- *           <span class="highlighter-nodeinfobar-tagname">Node name</span>
- *           <span class="highlighter-nodeinfobar-id">Node id</span>
- *           <span class="highlighter-nodeinfobar-classes">.someClass</span>
- *           <span class="highlighter-nodeinfobar-pseudo-classes">:hover</span>
- *         </hbox>
- *       </hbox>
- *       <box class="highlighter-nodeinfobar-arrow highlighter-nodeinfobar-arrow-bottom"/>
- *     </box>
- *   </box>
- * </stack>
+ *  <stack class="highlighter-container">
+ *    <box class="highlighter-outline-container">
+ *      <box class="highlighter-outline" />
+ *    </box>
+ *    <box class="highlighter-nodeinfobar-container">
+ *      <box class="highlighter-nodeinfobar-positioner" position="top/bottom">
+ *        <box class="highlighter-nodeinfobar-arrow highlighter-nodeinfobar-arrow-top"/>
+ *        <hbox class="highlighter-nodeinfobar">
+ *          <hbox class="highlighter-nodeinfobar-text">tagname#id.class1.class2</hbox>
+ *        </hbox>
+ *        <box class="highlighter-nodeinfobar-arrow highlighter-nodeinfobar-arrow-bottom"/>
+ *      </box>
+ *    </box>
+ *  </stack>
  */
-function BoxModelHighlighter(tabActor, inspector) {
+function BoxModelHighlighter(tabActor) {
   this.browser = tabActor.browser;
   this.win = tabActor.window;
   this.chromeDoc = this.browser.ownerDocument;
   this.chromeWin = this.chromeDoc.defaultView;
-  this._inspector = inspector;
 
   this.layoutHelpers = new LayoutHelpers(this.win);
   this.chromeLayoutHelper = new LayoutHelpers(this.chromeWin);
 
   this.transitionDisabler = null;
   this.pageEventsMuter = null;
   this._update = this._update.bind(this);
-  this.handleEvent = this.handleEvent.bind(this);
   this.currentNode = null;
 
-  EventEmitter.decorate(this);
   this._initMarkup();
 }
 
 BoxModelHighlighter.prototype = {
-  get zoom() {
-    return this.win.QueryInterface(Ci.nsIInterfaceRequestor)
-               .getInterface(Ci.nsIDOMWindowUtils).fullZoom;
-  },
-
   _initMarkup: function() {
     let stack = this.browser.parentNode;
 
-    this._highlighterContainer = this.chromeDoc.createElement("stack");
-    this._highlighterContainer.className = "highlighter-container";
-
-    this._svgRoot = this._createSVGNode("root", "svg", this._highlighterContainer);
-
-    this._boxModelContainer = this._createSVGNode("container", "g", this._svgRoot);
-
-    this._boxModelNodes = {
-      margin: this._createSVGNode("margin", "polygon", this._boxModelContainer),
-      border: this._createSVGNode("border", "polygon", this._boxModelContainer),
-      padding: this._createSVGNode("padding", "polygon", this._boxModelContainer),
-      content: this._createSVGNode("content", "polygon", this._boxModelContainer)
-    };
+    this.highlighterContainer = this.chromeDoc.createElement("stack");
+    this.highlighterContainer.className = "highlighter-container";
 
-    this._guideNodes = {
-      top: this._createSVGNode("guide-top", "line", this._svgRoot),
-      right: this._createSVGNode("guide-right", "line", this._svgRoot),
-      bottom: this._createSVGNode("guide-bottom", "line", this._svgRoot),
-      left: this._createSVGNode("guide-left", "line", this._svgRoot)
-    };
+    this.outline = this.chromeDoc.createElement("box");
+    this.outline.className = "highlighter-outline";
 
-    this._guideNodes.top.setAttribute("stroke-width", GUIDE_STROKE_WIDTH);
-    this._guideNodes.right.setAttribute("stroke-width", GUIDE_STROKE_WIDTH);
-    this._guideNodes.bottom.setAttribute("stroke-width", GUIDE_STROKE_WIDTH);
-    this._guideNodes.left.setAttribute("stroke-width", GUIDE_STROKE_WIDTH);
-
-    this._highlighterContainer.appendChild(this._svgRoot);
+    let outlineContainer = this.chromeDoc.createElement("box");
+    outlineContainer.appendChild(this.outline);
+    outlineContainer.className = "highlighter-outline-container";
+    this.highlighterContainer.appendChild(outlineContainer);
 
     let infobarContainer = this.chromeDoc.createElement("box");
     infobarContainer.className = "highlighter-nodeinfobar-container";
-    this._highlighterContainer.appendChild(infobarContainer);
+    this.highlighterContainer.appendChild(infobarContainer);
 
     // Insert the highlighter right after the browser
-    stack.insertBefore(this._highlighterContainer, stack.childNodes[1]);
+    stack.insertBefore(this.highlighterContainer, stack.childNodes[1]);
 
     // Building the infobar
     let infobarPositioner = this.chromeDoc.createElement("box");
     infobarPositioner.className = "highlighter-nodeinfobar-positioner";
     infobarPositioner.setAttribute("position", "top");
     infobarPositioner.setAttribute("disabled", "true");
 
     let nodeInfobar = this.chromeDoc.createElement("hbox");
@@ -423,74 +357,66 @@ BoxModelHighlighter.prototype = {
       idLabel: idLabel,
       classesBox: classesBox,
       pseudoClassesBox: pseudoClassesBox,
       positioner: infobarPositioner,
       barHeight: barHeight,
     };
   },
 
-  _createSVGNode: function(classPostfix, nodeType, parent) {
-    let node = this.chromeDoc.createElementNS(SVG_NS, nodeType);
-    node.setAttribute("class", "box-model-" + classPostfix);
-
-    parent.appendChild(node);
-
-    return node;
-  },
-
   /**
    * Destroy the nodes. Remove listeners.
    */
   destroy: function() {
     this.hide();
 
     this.chromeWin.clearTimeout(this.transitionDisabler);
     this.chromeWin.clearTimeout(this.pageEventsMuter);
 
+    this._contentRect = null;
+    this._highlightRect = null;
+    this.outline = null;
     this.nodeInfo = null;
 
-    this._highlighterContainer.remove();
-    this._highlighterContainer = null;
+    this.highlighterContainer.remove();
+    this.highlighterContainer = null;
 
-    this.rect = null;
-    this.win = null;
+    this.win = null
     this.browser = null;
     this.chromeDoc = null;
     this.chromeWin = null;
     this.currentNode = null;
   },
 
   /**
    * Show the highlighter on a given node
    *
    * @param {DOMNode} node
-   * @param {Object} options
-   *        Object used for passing options
    */
   show: function(node, options={}) {
-    this.currentNode = node;
+    if (!this.currentNode || node !== this.currentNode) {
+      this.currentNode = node;
 
-    this._showInfobar();
-    this._detachPageListeners();
-    this._attachPageListeners();
-    this._update();
-    this._trackMutations();
+      this._showInfobar();
+      this._computeZoomFactor();
+      this._detachPageListeners();
+      this._attachPageListeners();
+      this._update();
+      this._trackMutations();
 
-    if (options.scrollIntoView) {
-      this.chromeLayoutHelper.scrollIntoViewIfNeeded(node);
+      if (options.scrollIntoView) {
+        this.chromeLayoutHelper.scrollIntoViewIfNeeded(node);
+      }
     }
   },
 
   _trackMutations: function() {
     if (this.currentNode) {
       let win = this.currentNode.ownerDocument.defaultView;
-      this.currentNodeObserver = new win.MutationObserver(() => {
-        this._update();
-      });
+      this.currentNodeObserver = new win.MutationObserver(this._update);
       this.currentNodeObserver.observe(this.currentNode, {attributes: true});
     }
   },
 
   _untrackMutations: function() {
     if (this.currentNode) {
       if (this.currentNodeObserver) {
         // The following may fail with a "can't access dead object" exception
@@ -502,208 +428,136 @@ BoxModelHighlighter.prototype = {
       }
     }
   },
 
   /**
    * Update the highlighter on the current highlighted node (the one that was
    * passed as an argument to show(node)).
    * Should be called whenever node size or attributes change
-   * @param {Object} options
-   *        Object used for passing options. Valid options are:
-   *          - box: "content", "padding", "border" or "margin." This specifies
-   *            the box that the guides should outline. Default is content.
+   * @param {Boolean} brieflyDisableTransitions
+   *        In case _update is called during scrolling or repaint, set this
+   *        to true to avoid transitions
    */
-  _update: function(options={}) {
+  _update: function(brieflyDisableTransitions) {
     if (this.currentNode) {
-      if (this._highlightBoxModel(options)) {
-        this._showInfobar();
+      let rect = this.layoutHelpers.getDirtyRect(this.currentNode);
+
+      if (this._highlightRectangle(rect, brieflyDisableTransitions)) {
+        this._moveInfobar();
+        this._updateInfobar();
       } else {
         // Nothing to highlight (0px rectangle like a <script> tag for instance)
         this.hide();
       }
-      this.emit("ready");
     }
   },
 
   /**
    * Hide the highlighter, the outline and the infobar.
    */
   hide: function() {
     if (this.currentNode) {
       this._untrackMutations();
       this.currentNode = null;
-      this._hideBoxModel();
+      this._hideOutline();
       this._hideInfobar();
       this._detachPageListeners();
     }
-    this.emit("hide");
   },
 
   /**
    * Hide the infobar
    */
   _hideInfobar: function() {
+    this.nodeInfo.positioner.setAttribute("force-transitions", "true");
     this.nodeInfo.positioner.setAttribute("hidden", "true");
   },
 
   /**
    * Show the infobar
    */
   _showInfobar: function() {
     this.nodeInfo.positioner.removeAttribute("hidden");
-    this._updateInfobar();
+    this._moveInfobar();
+    this.nodeInfo.positioner.removeAttribute("force-transitions");
   },
 
   /**
-   * Hide the box model
+   * Hide the outline
    */
-  _hideBoxModel: function() {
-    this._svgRoot.setAttribute("hidden", "true");
+  _hideOutline: function() {
+    this.outline.setAttribute("hidden", "true");
   },
 
   /**
-   * Show the box model
+   * Show the outline
    */
-  _showBoxModel: function() {
-    this._svgRoot.removeAttribute("hidden");
+  _showOutline: function() {
+    this.outline.removeAttribute("hidden");
   },
 
   /**
-   * Highlight the box model.
+   * Highlight a rectangular region.
    *
-   * @param {Object} options
-   *        Object used for passing options. Valid options are:
-   *          - region: "content", "padding", "border" or "margin." This specifies
-   *            the region that the guides should outline. Default is content.
+   * @param {object} aRect
+   *        The rectangle region to highlight.
+   * @param {boolean} brieflyDisableTransitions
+   *        Set to true to avoid transitions during the highlighting
    * @return {boolean}
    *         True if the rectangle was highlighted, false otherwise.
    */
-  _highlightBoxModel: function(options) {
-    let isShown = false;
-
-    options.region = options.region || "content";
+  _highlightRectangle: function(aRect, brieflyDisableTransitions) {
+    if (!aRect) {
+      return false;
+    }
 
-    // TODO: Remove this polyfill
-    this.rect =
-      this.layoutHelpers.getAdjustedQuadsPolyfill(this.currentNode, "margin");
+    let oldRect = this._contentRect;
 
-    if (!this.rect) {
-      return null;
+    if (oldRect && aRect.top == oldRect.top && aRect.left == oldRect.left &&
+        aRect.width == oldRect.width && aRect.height == oldRect.height) {
+      this._showOutline();
+      return true; // same rectangle
     }
 
-    if (this.rect.bounds.width > 0 && this.rect.bounds.height > 0) {
-      for (let boxType in this._boxModelNodes) {
-        // TODO: Remove this polyfill
-        let {p1, p2, p3, p4} = boxType === "margin" ? this.rect :
-          this.layoutHelpers.getAdjustedQuadsPolyfill(this.currentNode, boxType);
+    let aRectScaled = this.layoutHelpers.getZoomedRect(this.win, aRect);
+    let isShown = false;
+
+    if (aRectScaled.left >= 0 && aRectScaled.top >= 0 &&
+        aRectScaled.width > 0 && aRectScaled.height > 0) {
 
-        let boxNode = this._boxModelNodes[boxType];
-        boxNode.setAttribute("points",
-                             p1.x + "," + p1.y + " " +
-                             p2.x + "," + p2.y + " " +
-                             p3.x + "," + p3.y + " " +
-                             p4.x + "," + p4.y);
+      // The bottom div and the right div are flexibles (flex=1).
+      // We don't need to resize them.
+      let top = "top:" + aRectScaled.top + "px;";
+      let left = "left:" + aRectScaled.left + "px;";
+      let width = "width:" + aRectScaled.width + "px;";
+      let height = "height:" + aRectScaled.height + "px;";
 
-        if (boxType === options.region) {
-          this._showGuides(p1, p2, p3, p4);
-        }
+      if (brieflyDisableTransitions) {
+        this._brieflyDisableTransitions();
       }
 
+      this.outline.setAttribute("style", top + left + width + height);
+
       isShown = true;
-      this._showBoxModel();
+      this._showOutline();
     } else {
       // Only return false if the element really is invisible.
       // A height of 0 and a non-0 width corresponds to a visible element that
       // is below the fold for instance
-      if (this.rect.width > 0 || this.rect.height > 0) {
+      if (aRectScaled.width > 0 || aRectScaled.height > 0) {
         isShown = true;
-        this._hideBoxModel();
-      }
-    }
-    return isShown;
-  },
-
-  /**
-   * We only want to show guides for horizontal and vertical edges as this helps
-   * to line them up. This method finds these edges and displays a guide there.
-   *
-   * @param  {DOMPoint} p1
-   *                    Point 1
-   * @param  {DOMPoint} p2
-   *                    Point 2
-   * @param  {DOMPoint} p3 [description]
-   *                    Point 3
-   * @param  {DOMPoint} p4 [description]
-   *                    Point 4
-   */
-  _showGuides: function(p1, p2, p3, p4) {
-    let allX = [p1.x, p2.x, p3.x, p4.x].sort();
-    let allY = [p1.y, p2.y, p3.y, p4.y].sort();
-    let toShowX = [];
-    let toShowY = [];
-
-    for (let arr of [allX, allY]) {
-      for (let i = 0; i < arr.length; i++) {
-        let val = arr[i];
-
-        if (i !== arr.lastIndexOf(val)) {
-          if (arr === allX) {
-            toShowX.push(val);
-          } else {
-            toShowY.push(val);
-          }
-          arr.splice(arr.lastIndexOf(val), 1);
-        }
+        this._hideOutline();
       }
     }
 
-    // Move guide into place or hide it if no valid co-ordinate was found.
-    this._updateGuide(this._guideNodes.top, toShowY[0]);
-    this._updateGuide(this._guideNodes.right, toShowX[1]);
-    this._updateGuide(this._guideNodes.bottom, toShowY[1]);
-    this._updateGuide(this._guideNodes.left, toShowX[0]);
-  },
-
-  /**
-   * Move a guide to the appropriate position and display it. If no point is
-   * passed then the guide is hidden.
-   *
-   * @param  {SVGLine} guide
-   *         The guide to update
-   * @param  {Integer} point
-   *         x or y co-ordinate. If this is undefined we hide the guide.
-   */
-  _updateGuide: function(guide, point=-1) {
-    if (point > 0) {
-      let offset = GUIDE_STROKE_WIDTH / 2;
+    this._contentRect = aRect; // save orig (non-scaled) rect
+    this._highlightRect = aRectScaled; // and save the scaled rect.
 
-      if (guide === this._guideNodes.top || guide === this._guideNodes.left) {
-        point -= offset;
-      } else {
-        point += offset;
-      }
-
-      if (guide === this._guideNodes.top || guide === this._guideNodes.bottom) {
-        guide.setAttribute("x1", 0);
-        guide.setAttribute("y1", point);
-        guide.setAttribute("x2", "100%");
-        guide.setAttribute("y2", point);
-      } else {
-        guide.setAttribute("x1", point);
-        guide.setAttribute("y1", 0);
-        guide.setAttribute("x2", point);
-        guide.setAttribute("y2", "100%");
-      }
-      guide.removeAttribute("hidden");
-      return true;
-    } else {
-      guide.setAttribute("hidden", "true");
-      return false;
-    }
+    return isShown;
   },
 
   /**
    * Update node information (tagName#id.class)
    */
   _updateInfobar: function() {
     if (this.currentNode) {
       // Tag name
@@ -720,52 +574,63 @@ BoxModelHighlighter.prototype = {
 
       // Pseudo-classes
       let pseudos = PSEUDO_CLASSES.filter(pseudo => {
         return DOMUtils.hasPseudoClassLock(this.currentNode, pseudo);
       }, this);
 
       let pseudoBox = this.nodeInfo.pseudoClassesBox;
       pseudoBox.textContent = pseudos.join("");
-
-      this._moveInfobar();
     }
   },
 
   /**
    * Move the Infobar to the right place in the highlighter.
    */
   _moveInfobar: function() {
-    if (this.rect) {
-      let bounds = this.rect.bounds;
+    if (this._highlightRect) {
       let winHeight = this.win.innerHeight * this.zoom;
       let winWidth = this.win.innerWidth * this.zoom;
 
+      let rect = {top: this._highlightRect.top,
+                  left: this._highlightRect.left,
+                  width: this._highlightRect.width,
+                  height: this._highlightRect.height};
+
+      rect.top = Math.max(rect.top, 0);
+      rect.left = Math.max(rect.left, 0);
+      rect.width = Math.max(rect.width, 0);
+      rect.height = Math.max(rect.height, 0);
+
+      rect.top = Math.min(rect.top, winHeight);
+      rect.left = Math.min(rect.left, winWidth);
+
       this.nodeInfo.positioner.removeAttribute("disabled");
       // Can the bar be above the node?
-      if (bounds.top < this.nodeInfo.barHeight) {
+      if (rect.top < this.nodeInfo.barHeight) {
         // No. Can we move the toolbar under the node?
-        if (bounds.bottom + this.nodeInfo.barHeight > winHeight) {
+        if (rect.top + rect.height +
+            this.nodeInfo.barHeight > winHeight) {
           // No. Let's move it inside.
-          this.nodeInfo.positioner.style.top = bounds.top + "px";
+          this.nodeInfo.positioner.style.top = rect.top + "px";
           this.nodeInfo.positioner.setAttribute("position", "overlap");
         } else {
           // Yes. Let's move it under the node.
-          this.nodeInfo.positioner.style.top = bounds.bottom - INFO_BAR_OFFSET + "px";
+          this.nodeInfo.positioner.style.top = rect.top + rect.height + "px";
           this.nodeInfo.positioner.setAttribute("position", "bottom");
         }
       } else {
         // Yes. Let's move it on top of the node.
         this.nodeInfo.positioner.style.top =
-          bounds.top + INFO_BAR_OFFSET - this.nodeInfo.barHeight + "px";
+          rect.top - this.nodeInfo.barHeight + "px";
         this.nodeInfo.positioner.setAttribute("position", "top");
       }
 
       let barWidth = this.nodeInfo.positioner.getBoundingClientRect().width;
-      let left = bounds.right - bounds.width / 2 - barWidth / 2;
+      let left = rect.left + rect.width / 2 - barWidth / 2;
 
       // Make sure the whole infobar is visible
       if (left < 0) {
         left = 0;
         this.nodeInfo.positioner.setAttribute("hide-arrow", "true");
       } else {
         if (left + barWidth > winWidth) {
           left = winWidth - barWidth;
@@ -778,51 +643,74 @@ BoxModelHighlighter.prototype = {
     } else {
       this.nodeInfo.positioner.style.left = "0";
       this.nodeInfo.positioner.style.top = "0";
       this.nodeInfo.positioner.setAttribute("position", "top");
       this.nodeInfo.positioner.setAttribute("hide-arrow", "true");
     }
   },
 
-  _attachPageListeners: function() {
-    if (this.currentNode) {
-      let win = this.currentNode.ownerGlobal;
+  /**
+   * Store page zoom factor.
+   */
+  _computeZoomFactor: function() {
+    this.zoom =
+      this.win.QueryInterface(Ci.nsIInterfaceRequestor)
+      .getInterface(Ci.nsIDOMWindowUtils)
+      .fullZoom;
+  },
 
-      win.addEventListener("scroll", this, false);
-      win.addEventListener("resize", this, false);
-      win.addEventListener("MozAfterPaint", this, false);
-    }
+  _attachPageListeners: function() {
+    this.browser.addEventListener("resize", this, true);
+    this.browser.addEventListener("scroll", this, true);
+    this.browser.addEventListener("MozAfterPaint", this, true);
   },
 
   _detachPageListeners: function() {
-    if (this.currentNode) {
-      let win = this.currentNode.ownerGlobal;
-
-      win.removeEventListener("scroll", this, false);
-      win.removeEventListener("resize", this, false);
-      win.removeEventListener("MozAfterPaint", this, false);
-    }
+    this.browser.removeEventListener("resize", this, true);
+    this.browser.removeEventListener("scroll", this, true);
+    this.browser.removeEventListener("MozAfterPaint", this, true);
   },
 
   /**
    * Generic event handler.
    *
    * @param nsIDOMEvent aEvent
    *        The DOM event object.
    */
   handleEvent: function(event) {
     switch (event.type) {
       case "resize":
+        this._computeZoomFactor();
+        break;
       case "MozAfterPaint":
       case "scroll":
-        this._update();
+        this._update(true);
         break;
     }
   },
+
+  /**
+   * Disable the CSS transitions for a short time to avoid laggy animations
+   * during scrolling or resizing.
+   */
+  _brieflyDisableTransitions: function() {
+    if (this.transitionDisabler) {
+      this.chromeWin.clearTimeout(this.transitionDisabler);
+    } else {
+      this.outline.setAttribute("disable-transitions", "true");
+      this.nodeInfo.positioner.setAttribute("disable-transitions", "true");
+    }
+    this.transitionDisabler =
+      this.chromeWin.setTimeout(() => {
+        this.outline.removeAttribute("disable-transitions");
+        this.nodeInfo.positioner.removeAttribute("disable-transitions");
+        this.transitionDisabler = null;
+      }, 500);
+  }
 };
 
 /**
  * The SimpleOutlineHighlighter is a class that has the same API than the
  * BoxModelHighlighter, but adds a pseudo-class on the target element itself
  * to draw a simple outline.
  * It is used by the HighlighterActor too, but in case the more complex
  * BoxModelHighlighter can't be attached (which is the case for FirefoxOS and
--- a/toolkit/devtools/server/actors/inspector.js
+++ b/toolkit/devtools/server/actors/inspector.js
@@ -844,22 +844,16 @@ var WalkerActor = protocol.ActorClass({
     },
     "picker-node-picked" : {
       type: "pickerNodePicked",
       node: Arg(0, "disconnectedNode")
     },
     "picker-node-hovered" : {
       type: "pickerNodeHovered",
       node: Arg(0, "disconnectedNode")
-    },
-    "highlighter-ready" : {
-      type: "highlighter-ready"
-    },
-    "highlighter-hide" : {
-      type: "highlighter-hide"
     }
   },
 
   /**
    * Create the WalkerActor
    * @param DebuggerServerConnection conn
    *    The server connection.
    */
@@ -1195,17 +1189,17 @@ var WalkerActor = protocol.ActorClass({
     if (maxNodes == -1) {
       maxNodes = Number.MAX_VALUE;
     }
 
     // We're going to create a few document walkers with the same filter,
     // make it easier.
     let filteredWalker = (node) => {
       return documentWalker(node, this.rootWin, options.whatToShow);
-    };
+    }
 
     // Need to know the first and last child.
     let rawNode = node.rawNode;
     let firstChild = filteredWalker(rawNode).firstChild();
     let lastChild = filteredWalker(rawNode).lastChild();
 
     if (!firstChild) {
       // No children, we're done.
@@ -1386,25 +1380,17 @@ var WalkerActor = protocol.ActorClass({
   /**
    * Return a NodeListActor with all nodes that match the given selector.
    * See https://developer.mozilla.org/en-US/docs/Web/API/Element.querySelectorAll
    *
    * @param NodeActor baseNode
    * @param string selector
    */
   querySelectorAll: method(function(baseNode, selector) {
-    let nodeList = null;
-
-    try {
-      nodeList = baseNode.rawNode.querySelectorAll(selector);
-    } catch(e) {
-      // Bad selector. Do nothing as the selector can come from a searchbox.
-    }
-
-    return new NodeListActor(this, nodeList);
+    return new NodeListActor(this, baseNode.rawNode.querySelectorAll(selector));
   }, {
     request: {
       node: Arg(0, "domnode"),
       selector: Arg(1)
     },
     response: {
       list: RetVal("domnodelist")
     }
@@ -2547,27 +2533,27 @@ var InspectorActor = protocol.ActorClass
     return this._pageStylePromise;
   }, {
     request: {},
     response: {
       pageStyle: RetVal("pagestyle")
     }
   }),
 
-  getHighlighter: method(function (autohide) {
+  getHighlighter: method(function () {
     if (this._highlighterPromise) {
       return this._highlighterPromise;
     }
 
     this._highlighterPromise = this.getWalker().then(walker => {
-      return HighlighterActor(this, autohide);
+      return HighlighterActor(this);
     });
     return this._highlighterPromise;
   }, {
-    request: { autohide: Arg(0, "boolean") },
+    request: {},
     response: {
       highligter: RetVal("highlighter")
     }
   }),
 
   /**
    * Get the node's image data if any (for canvas and img nodes).
    * Returns an imageData object with the actual data being a LongStringActor