Tried splitting some patches apart, hope I didn't break much.
authorDave Camp <dcamp@mozilla.com>
Sat, 15 Jun 2013 19:52:56 -0700
changeset 7 90ff8b9e50c0095334a1bbd704dfa80ad9b45df7
parent 6 746f08f768e729f23e730500294fa0c66c5ff892
child 8 35e660233e731e8037f6d5e2e3ffb222b319dde6
push id8
push userdcamp@campd.org
push dateSun, 16 Jun 2013 02:53:01 +0000
Tried splitting some patches apart, hope I didn't break much.
actor-markup-fixes.diff
console-padend.diff
highlighter-fix.diff
inspector-panel-default-node.diff
inspector-remote-breadcrumbs.diff
remote-delete-node.diff
remote-markup.diff
selection-fixes.diff
series
warning-fixes.diff
new file mode 100644
--- /dev/null
+++ b/actor-markup-fixes.diff
@@ -0,0 +1,205 @@
+# HG changeset patch
+# Parent 4fd10515d84e76dde3201aeb27240a82f18e1649
+diff --git a/toolkit/devtools/server/actors/inspector.js b/toolkit/devtools/server/actors/inspector.js
+--- a/toolkit/devtools/server/actors/inspector.js
++++ b/toolkit/devtools/server/actors/inspector.js
+@@ -122,23 +122,33 @@ var NodeActor = protocol.ActorClass({
+    * from its associated walker.
+    */
+   get conn() this.walker.conn,
+ 
+   // Returns the JSON representation of this object over the wire.
+   form: function(detail) {
+     let parentNode = this.walker.parentNode(this);
+ 
++    // Estimate the number of children.
++    let numChildren = this.rawNode.childNodes.length;
++    if (numChildren === 0) {
++      // This might be an iframe with virtual children.
++      let walker = documentWalker(this.rawNode);
++      if (walker.firstChild()) {
++        numChildren = 1;
++      }
++    }
++
+     let form = {
+       actor: this.actorID,
+       parent: parentNode ? parentNode.actorID : undefined,
+       nodeType: this.rawNode.nodeType,
+       namespaceURI: this.namespaceURI,
+       nodeName: this.rawNode.nodeName,
+-      numChildren: this.rawNode.childNodes.length,
++      numChildren: numChildren,
+ 
+       // doctype attributes
+       name: this.rawNode.name,
+       publicId: this.rawNode.publicId,
+       systemId: this.rawNode.systemId,
+ 
+       attrs: this.writeAttrs(),
+ 
+@@ -430,17 +440,19 @@ let NodeFront = protocol.FrontClass(Node
+    */
+   rawNode: function(rawNode) {
+     if (!this.conn._transport._serverConnection) {
+       console.warn("Tried to use rawNode on a remote connection.");
+       return null;
+     }
+     let actor = this.conn._transport._serverConnection.getActor(this.actorID);
+     if (!actor) {
+-      throw new Error("Could not find client side for actor " + this.actorID);
++      // Can happen if we try to get the raw node for an already-expired
++      // actor.
++      return null;
+     }
+     return actor.rawNode;
+   }
+ });
+ 
+ /**
+  * Returned from any call that might return a node that isn't connected to root by
+  * nodes the child has seen, such as querySelector.
+@@ -1464,31 +1476,35 @@ var WalkerActor = protocol.ActorClass({
+ 
+   /**
+    * Handles mutations from the DOM mutation observer API.
+    *
+    * @param array[MutationRecord] mutations
+    *    See https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver#MutationRecord
+    */
+   onMutations: function(mutations) {
++    dump("STARTING MUTATION\n");
+     for (let change of mutations) {
++      dump("GOT: " + change.type + "\n");
+       let targetActor = this._refMap.get(change.target);
+       if (!targetActor) {
+         continue;
+       }
+       let targetNode = change.target;
+       let mutation = {
+         type: change.type,
+         target: targetActor.actorID,
+       }
+ 
+       if (mutation.type === "attributes") {
+         mutation.attributeName = change.attributeName;
+         mutation.attributeNamespace = change.attributeNamespace || undefined;
+         mutation.newValue = targetNode.getAttribute(mutation.attributeName);
++        dump("\tname: " + mutation.attributeName + "\n");
++        dump("\tnewValue: " + mutation.newValue + "\n")
+       } else if (mutation.type === "characterData") {
+         if (targetNode.nodeValue.length > gValueSummaryLength) {
+           mutation.newValue = targetNode.nodeValue.substring(0, gValueSummaryLength);
+           mutation.incompleteValue = true;
+         } else {
+           mutation.newValue = targetNode.nodeValue;
+         }
+       } else if (mutation.type === "childList") {
+@@ -1522,16 +1538,17 @@ var WalkerActor = protocol.ActorClass({
+           addedActors.push(addedActor.actorID);
+         }
+         mutation.numChildren = change.target.childNodes.length;
+         mutation.removed = removedActors;
+         mutation.added = addedActors;
+       }
+       this.queueMutation(mutation);
+     }
++    dump("DONE WITH MUTATIONS\n");
+   },
+ 
+   onFrameLoad: function(window) {
+     let frame = window.frameElement;
+     let frameActor = this._refMap.get(frame);
+     if (!frameActor) {
+       return;
+     }
+@@ -1552,16 +1569,17 @@ var WalkerActor = protocol.ActorClass({
+         return true;
+       }
+       win = win.frameElement;
+     }
+     return false;
+   },
+ 
+   onFrameUnload: function(window) {
++    dump("------UNLOADING FRAME\n");
+     // Any retained orphans that belong to this document
+     // or its children need to be released, and a mutation sent
+     // to notify of that.
+     let releasedOrphans = [];
+ 
+     for (let retained of this._retainedOrphans) {
+       if (Cu.isDeadWrapper(retained.rawNode) ||
+           this._childOfWindow(window, retained.rawNode)) {
+@@ -1759,16 +1777,20 @@ var WalkerFront = exports.WalkerFront = 
+             removedFronts.push(removedFront);
+           }
+           for (let added of change.added) {
+             let addedFront = this.get(added);
+             if (!addedFront) {
+               console.error("Got an addition of an actor we didn't know about: " + added);
+               continue;
+             }
++            dump("ADDING " + addedFront.actorID + " TO " + targetFront.actorID + "\n");
++            if (this._orphaned.has(addedFront)) {
++              dump("IT WAS AN ORPHAN\n");
++            }
+             addedFront.reparent(targetFront)
+ 
+             // The actor is reconnected to the ownership tree, unorphan
+             // it.
+             this._orphaned.delete(addedFront);
+             addedFronts.push(addedFront);
+           }
+           // Before passing to users, replace the added and removed actor
+@@ -1784,16 +1806,17 @@ var WalkerFront = exports.WalkerFront = 
+             if (child.nodeType === Ci.nsIDOMNode.DOCUMENT_NODE) {
+               console.trace("Got an unexpected frameLoad in the inspector, please file a bug on bugzilla.mozilla.org!");
+             }
+           }
+         } else if (change.type === "documentUnload") {
+           // We try to give fronts instead of actorIDs, but these fronts need
+           // to be destroyed now.
+           emittedMutation.target = targetFront.actorID;
++          emittedMutation.targetParent = targetFront.parentNode();
+ 
+           // Release the document node and all of its children, even retained.
+           this._releaseFront(targetFront, true);
+         } else if (change.type === "unretained") {
+           // Retained orphans were force-released without the intervention of
+           // client (probably a navigated frame).
+           for (let released of change.nodes) {
+             let releasedFront = this.get(released);
+@@ -1844,20 +1867,31 @@ var WalkerFront = exports.WalkerFront = 
+     let walkerActor = this.conn._transport._serverConnection.getActor(this.actorID);
+     if (!walkerActor) {
+       throw Error("Could not find client side for actor " + this.actorID);
+     }
+     let nodeActor = walkerActor._ref(rawNode);
+ 
+     // Pass the node through a read/write pair to create the client side actor.
+     let nodeType = types.getType("domnode");
++    dump("BEFORE NODE READ\n");
+     let returnNode = nodeType.read(nodeType.write(nodeActor, walkerActor), this);
++    dump("AFTER NODE READ\n");
++    let top = returnNode;
+     let extras = walkerActor.parents(nodeActor);
+     for (let extraActor of extras) {
+-      nodeType.read(nodeType.write(extraActor, walkerActor), this);
++      dump("BEFORE PARENT READ\n");
++      top = nodeType.read(nodeType.write(extraActor, walkerActor), this);
++      dump("AFTER PARENT READ\n");
++    }
++
++    if (top !== this.rootNode) {
++      // Imported an already-orphaned node.
++      this._orphaned.add(top);
++      walkerActor._orphaned.add(this.conn._transport._serverConnection.getActor(top.actorID));
+     }
+     return returnNode;
+   }
+ });
+ 
+ /**
+  * Convenience API for building a list of attribute modifications
+  * for the `modifyAttributes` request.
new file mode 100644
--- /dev/null
+++ b/console-padend.diff
@@ -0,0 +1,24 @@
+# HG changeset patch
+# Parent f838ce3415e147cd2787f14fd75cd48caf95a838
+diff --git a/toolkit/devtools/Console.jsm b/toolkit/devtools/Console.jsm
+--- a/toolkit/devtools/Console.jsm
++++ b/toolkit/devtools/Console.jsm
+@@ -69,17 +69,17 @@ function fmt(aStr, aMaxLen, aMinLen, aOp
+       let end = aStr.substring((aStr.length - (aMaxLen / 2)) + 1);
+       return start + "_" + end;
+     }
+     else {
+       return aStr.substring(0, aMaxLen - 1) + "_";
+     }
+   }
+   if (aStr.length < aMinLen) {
+-    return Array(aMinLen - aStr.length + 1).join(" ") + aStr;
++    return aStr + Array(aMinLen - aStr.length + 1).join(" ");
+   }
+   return aStr;
+ }
+ 
+ /**
+  * Utility to extract the constructor name of an object.
+  * Object.toString gives: "[object ?????]"; we want the "?????".
+  *
new file mode 100644
--- /dev/null
+++ b/highlighter-fix.diff
@@ -0,0 +1,32 @@
+# HG changeset patch
+# Parent 258d8ec59acdf4e683828940ecf0257e5a4cb1c2
+
+diff --git a/browser/devtools/inspector/highlighter.js b/browser/devtools/inspector/highlighter.js
+--- a/browser/devtools/inspector/highlighter.js
++++ b/browser/devtools/inspector/highlighter.js
+@@ -223,16 +223,25 @@ Highlighter.prototype = {
+     }
+   },
+ 
+   /**
+    * Update the highlighter size and position.
+    */
+   invalidateSize: function Highlighter_invalidateSize()
+   {
++    // The highlighter runs locally while the selection runs remotely,
++    // so we can't quite trust the selection's isConnected to protect us
++    // here, do the check manually.
++    if (!this.selection.node ||
++        !this.selection.node.ownerDocument ||
++        !this.selection.node.ownerDocument.defaultView) {
++      return;
++    }
++
+     let canHiglightNode = this.selection.isNode() &&
+                           this.selection.isConnected() &&
+                           this.selection.isElementNode();
+ 
+     if (!canHiglightNode)
+       return;
+ 
+     let clientRect = this.selection.node.getBoundingClientRect();
new file mode 100644
--- /dev/null
+++ b/inspector-panel-default-node.diff
@@ -0,0 +1,79 @@
+# HG changeset patch
+# Parent 5a3c75718c6b1fb4ef114d5fac982b03889af6d1
+diff --git a/browser/devtools/inspector/inspector-panel.js b/browser/devtools/inspector/inspector-panel.js
+--- a/browser/devtools/inspector/inspector-panel.js
++++ b/browser/devtools/inspector/inspector-panel.js
+@@ -152,24 +152,34 @@ InspectorPanel.prototype = {
+ 
+     return deferred.promise;
+   },
+ 
+   /**
+    * Return a promise that will resolve to the default node for selection.
+    */
+   _getDefaultNodeForSelection : function() {
++    if (this._defaultNode) {
++      return this._defaultNode;
++    }
++    let walker = this.walker;
+     // if available set body node as default selected node
+     // else set documentElement
+-    return this.walker.querySelector(this.walker.rootNode, "body").then(front => {
++    return walker.querySelector(this.walker.rootNode, "body").then(front => {
+       if (front) {
+         return front;
+       }
+       return this.walker.documentElement(this.walker.rootNode);
+-    });
++    }).then(node => {
++      if (walker !== this.walker) {
++        promise.reject(null);
++      }
++      this._defaultNode = node;
++      return node;
++    })
+   },
+ 
+   /**
+    * Selection object (read only)
+    */
+   get selection() {
+     return this._selection;
+   },
+@@ -272,16 +282,17 @@ InspectorPanel.prototype = {
+ 
+   /**
+    * Reset the inspector on navigate away.
+    */
+   onNavigatedAway: function InspectorPanel_onNavigatedAway(event, payload) {
+     let newWindow = payload._navPayload || payload;
+     this.walker.release().then(null, console.error);
+     this.walker = null;
++    this._defaultNode = null;
+     this.selection.setNodeFront(null);
+     this.selection.setWalker(null);
+     this._destroyMarkup();
+     this.isDirty = false;
+ 
+     this.target.inspector.getWalker().then(walker => {
+       if (this._destroyPromise) {
+         walker.release().then(null, console.error);
+@@ -387,17 +398,17 @@ InspectorPanel.prototype = {
+   },
+ 
+   /**
+    * When a node is deleted, select its parent node.
+    */
+   onDetached: function InspectorPanel_onDetached(event, parentNode) {
+     this.cancelLayoutChange();
+     this.breadcrumbs.cutAfter(this.breadcrumbs.indexOf(parentNode));
+-    this.selection.setNodeFront(parentNode, "detached");
++    this.selection.setNodeFront(parentNode ? parentNode : this._defaultNode, "detached");
+   },
+ 
+   /**
+    * Destroy the inspector.
+    */
+   destroy: function InspectorPanel__destroy() {
+     if (this._destroyPromise) {
+       return this._destroyPromise;
--- a/inspector-remote-breadcrumbs.diff
+++ b/inspector-remote-breadcrumbs.diff
@@ -1,14 +1,14 @@
 # HG changeset patch
 # User Dave Camp <dcamp@mozilla.com>
 # Date 1370640819 25200
 #      Fri Jun 07 14:33:39 2013 -0700
 # Node ID 8b49065448a6038dad3171180ecb0ab2996e9a99
-# Parent  ee78b8f0ffa56f2fb92f250e49ad3f53492d60a3
+# Parent 68d0be9dd4c70b190d96d293c841ec19880ae77e
 [mq]: inspector-remote-breadcrumbs.diff
 
 diff --git a/browser/devtools/inspector/breadcrumbs.js b/browser/devtools/inspector/breadcrumbs.js
 --- a/browser/devtools/inspector/breadcrumbs.js
 +++ b/browser/devtools/inspector/breadcrumbs.js
 @@ -7,29 +7,44 @@
  const {Cc, Cu, Ci} = require("chrome");
  
@@ -538,35 +538,17 @@ diff --git a/browser/devtools/inspector/
  }
  
  XPCOMUtils.defineLazyGetter(this, "DOMUtils", function () {
    return Cc["@mozilla.org/inspector/dom-utils;1"].getService(Ci.inIDOMUtils);
  });
 diff --git a/browser/devtools/inspector/inspector-panel.js b/browser/devtools/inspector/inspector-panel.js
 --- a/browser/devtools/inspector/inspector-panel.js
 +++ b/browser/devtools/inspector/inspector-panel.js
-@@ -7,16 +7,17 @@
- const {Cc, Ci, Cu, Cr} = require("chrome");
- 
- Cu.import("resource://gre/modules/Services.jsm");
- 
- let Promise = require("sdk/core/promise");
- let EventEmitter = require("devtools/shared/event-emitter");
- let {CssLogic} = require("devtools/styleinspector/css-logic");
- 
-+require("devtools/inspector/breadcrumbs");
- loader.lazyGetter(this, "MarkupView", () => require("devtools/markupview/markup-view").MarkupView);
- loader.lazyGetter(this, "Selection", () => require("devtools/inspector/selection").Selection);
- loader.lazyGetter(this, "HTMLBreadcrumbs", () => require("devtools/inspector/breadcrumbs").HTMLBreadcrumbs);
- loader.lazyGetter(this, "Highlighter", () => require("devtools/inspector/highlighter").Highlighter);
- loader.lazyGetter(this, "ToolSidebar", () => require("devtools/framework/sidebar").ToolSidebar);
- loader.lazyGetter(this, "SelectorSearch", () => require("devtools/inspector/selector-search").SelectorSearch);
- 
- const LAYOUT_CHANGE_TIMER = 250;
-@@ -70,17 +71,17 @@ InspectorPanel.prototype = {
+@@ -70,17 +70,17 @@ InspectorPanel.prototype = {
      this.nodemenu.addEventListener("popupshowing", this._setupNodeMenu, true);
      this.nodemenu.addEventListener("popuphiding", this._resetNodeMenu, true);
  
      // Create an empty selection
      this._selection = new Selection(this.walker);
      this.onNewSelection = this.onNewSelection.bind(this);
      this.selection.on("new-node-front", this.onNewSelection);
      this.onBeforeNewSelection = this.onBeforeNewSelection.bind(this);
@@ -575,17 +557,17 @@ diff --git a/browser/devtools/inspector/
      this.onDetached = this.onDetached.bind(this);
      this.selection.on("detached-front", this.onDetached);
  
      this.breadcrumbs = new HTMLBreadcrumbs(this);
  
      if (this.target.isLocalTab) {
        this.browser = this.target.tab.linkedBrowser;
        this.scheduleLayoutChange = this.scheduleLayoutChange.bind(this);
-@@ -304,16 +305,79 @@ InspectorPanel.prototype = {
+@@ -304,16 +304,79 @@ InspectorPanel.prototype = {
      });
    },
  
    /**
     * When a new node is selected.
     */
    onNewSelection: function InspectorPanel_onNewSelection() {
      this.cancelLayoutChange();
@@ -655,17 +637,17 @@ diff --git a/browser/devtools/inspector/
    },
  
    /**
     * When a new node is selected, before the selection has changed.
     */
    onBeforeNewSelection: function InspectorPanel_onBeforeNewSelection(event,
                                                                       node) {
      if (this.breadcrumbs.indexOf(node) == -1) {
-@@ -340,16 +404,17 @@ InspectorPanel.prototype = {
+@@ -340,16 +403,17 @@ InspectorPanel.prototype = {
      }
      if (this.walker) {
        this._destroyPromise = this.walker.release().then(null, console.error);
        delete this.walker;
      } else {
        this._destroyPromise = Promise.resolve(null);
      }
  
@@ -673,17 +655,17 @@ diff --git a/browser/devtools/inspector/
      this.cancelLayoutChange();
  
      if (this.browser) {
        this.browser.removeEventListener("resize", this.scheduleLayoutChange, true);
        this.browser = null;
      }
  
      this.target.off("navigate", this.onNavigatedAway);
-@@ -371,16 +436,17 @@ InspectorPanel.prototype = {
+@@ -371,16 +435,17 @@ InspectorPanel.prototype = {
      this.sidebar = null;
  
      this.nodemenu.removeEventListener("popupshowing", this._setupNodeMenu, true);
      this.nodemenu.removeEventListener("popuphiding", this._resetNodeMenu, true);
      this.breadcrumbs.destroy();
      this.searchSuggestions.destroy();
      this.selection.off("new-node-front", this.onNewSelection);
      this.selection.off("before-new-node", this.onBeforeNewSelection);
@@ -691,17 +673,17 @@ diff --git a/browser/devtools/inspector/
      this.selection.off("detached-front", this.onDetached);
      this._destroyMarkup();
      this._selection.destroy();
      this._selection = null;
      this.panelWin.inspector = null;
      this.target = null;
      this.panelDoc = null;
      this.panelWin = null;
-@@ -512,17 +578,17 @@ InspectorPanel.prototype = {
+@@ -512,17 +577,17 @@ InspectorPanel.prototype = {
  
    /**
     * Toggle a pseudo class.
     */
    togglePseudoClass: function InspectorPanel_togglePseudoClass(aPseudo) {
      if (this.selection.isElementNode()) {
        if (DOMUtils.hasPseudoClassLock(this.selection.node, aPseudo)) {
          this.breadcrumbs.nodeHierarchy.forEach(function(crumb) {
@@ -710,17 +692,17 @@ diff --git a/browser/devtools/inspector/
          });
        } else {
          let hierarchical = aPseudo == ":hover" || aPseudo == ":active";
          let node = this.selection.node;
          do {
            DOMUtils.addPseudoClassLock(node, aPseudo);
            node = node.parentNode;
          } while (hierarchical && node.parentNode)
-@@ -533,17 +599,17 @@ InspectorPanel.prototype = {
+@@ -533,17 +598,17 @@ InspectorPanel.prototype = {
    },
  
    /**
     * Clear any pseudo-class locks applied to the current hierarchy.
     */
    clearPseudoClasses: function InspectorPanel_clearPseudoClasses() {
      this.breadcrumbs.nodeHierarchy.forEach(function(crumb) {
        try {
--- a/remote-delete-node.diff
+++ b/remote-delete-node.diff
@@ -1,15 +1,15 @@
 # HG changeset patch
-# Parent 1f1c8d67e62ed6dd5eb6a869828269451e171987
+# Parent dfcd2af58c107ea3f347a3b99d4a441ba1057e40
 
 diff --git a/browser/devtools/inspector/inspector-panel.js b/browser/devtools/inspector/inspector-panel.js
 --- a/browser/devtools/inspector/inspector-panel.js
 +++ b/browser/devtools/inspector/inspector-panel.js
-@@ -644,34 +644,42 @@ InspectorPanel.prototype = {
+@@ -631,34 +631,42 @@ InspectorPanel.prototype = {
    /**
     * Copy the innerHTML of the selected Node to the clipboard.
     */
    copyInnerHTML: function InspectorPanel_copyInnerHTML()
    {
      if (!this.selection.isNode()) {
        return;
      }
@@ -50,17 +50,17 @@ diff --git a/browser/devtools/inspector/
    },
  
    /**
     * Copy a unique selector of the selected Node to the clipboard.
     */
    copyUniqueSelector: function InspectorPanel_copyUniqueSelector()
    {
      if (!this.selection.isNode()) {
-@@ -694,18 +702,17 @@ InspectorPanel.prototype = {
+@@ -681,18 +689,17 @@ InspectorPanel.prototype = {
      }
  
      // If the markup panel is active, use the markup panel to delete
      // the node, making this an undoable action.
      if (this.markup) {
        this.markup.deleteNode(this.selection.nodeFront);
      } else {
        // remove the node from content
@@ -104,17 +104,17 @@ diff --git a/browser/devtools/inspector/
      deleteRootNode();
    }
  
    function deleteRootNode() {
      inspector.selection.setNode(doc.documentElement);
 diff --git a/browser/devtools/markupview/markup-view.js b/browser/devtools/markupview/markup-view.js
 --- a/browser/devtools/markupview/markup-view.js
 +++ b/browser/devtools/markupview/markup-view.js
-@@ -231,38 +231,38 @@ MarkupView.prototype = {
+@@ -225,38 +225,38 @@ MarkupView.prototype = {
    },
  
    /**
     * Delete a node from the DOM.
     * This is an undoable action.
     */
    deleteNode: function MC__deleteNode(aNode)
    {
@@ -160,17 +160,17 @@ diff --git a/browser/devtools/markupview
    },
  
    /**
     * If an editable item is focused, select its container.
     */
    _onFocus: function MC__onFocus(aEvent) {
      let parent = aEvent.target;
      while (!parent.container) {
-@@ -597,16 +597,19 @@ MarkupView.prototype = {
+@@ -588,16 +588,19 @@ MarkupView.prototype = {
      // centered node.
      let centered = this._checkSelectionVisible(aContainer);
  
      // Children aren't updated yet, but clear the childrenDirty flag anyway.
      // If the dirty flag is re-set while we're fetching we'll need to fetch
      // again.
      aContainer.childrenDirty = false;
      let updatePromise = this._getVisibleChildren(aContainer, centered).then(children => {
@@ -180,37 +180,16 @@ diff --git a/browser/devtools/markupview
        this._queuedChildUpdates.delete(aContainer);
  
        // If children are dirty, we got a change notification for this node
        // while the request was in progress, we need to do it again.
        if (aContainer.childrenDirty) {
          return this._updateChildren(aContainer, centered);
        }
  
-diff --git a/browser/devtools/shared/LayoutHelpers.jsm b/browser/devtools/shared/LayoutHelpers.jsm
---- a/browser/devtools/shared/LayoutHelpers.jsm
-+++ b/browser/devtools/shared/LayoutHelpers.jsm
-@@ -37,17 +37,16 @@ this.LayoutHelpers = LayoutHelpers = {
-     // 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) {
--      Cu.import("resource://gre/modules/devtools/Console.jsm", {}).console.trace();
-       // 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);
 diff --git a/toolkit/devtools/server/actors/inspector.js b/toolkit/devtools/server/actors/inspector.js
 --- a/toolkit/devtools/server/actors/inspector.js
 +++ b/toolkit/devtools/server/actors/inspector.js
 @@ -1387,16 +1387,48 @@ var WalkerActor = protocol.ActorClass({
      request: {
        node: Arg(0, "domnode")
      },
      response: {
--- a/remote-markup.diff
+++ b/remote-markup.diff
@@ -1,72 +1,24 @@
 # HG changeset patch
 # User Dave Camp <dcamp@mozilla.com>
 # Date 1370924326 25200
 #      Mon Jun 10 21:18:46 2013 -0700
 # Node ID 327e1698efad6b10f6c9099aa65c87e0e4819532
-# Parent 31be65d87fc59d72a5c6d6ff5a8b7c99ef146d58
+# Parent 500dd317824d2f0dbeb0b5544d23384fca41cd33
 imported patch remote-markup.diff
 * * *
 imported patch markup-fixes.diff
 * * *
 [mq]: fucking-around.diff
 
-diff --git a/browser/devtools/inspector/highlighter.js b/browser/devtools/inspector/highlighter.js
---- a/browser/devtools/inspector/highlighter.js
-+++ b/browser/devtools/inspector/highlighter.js
-@@ -223,16 +223,25 @@ Highlighter.prototype = {
-     }
-   },
- 
-   /**
-    * Update the highlighter size and position.
-    */
-   invalidateSize: function Highlighter_invalidateSize()
-   {
-+    // The highlighter runs locally while the selection runs remotely,
-+    // so we can't quite trust the selection's isConnected to protect us
-+    // here, do the check manually.
-+    if (!this.selection.node ||
-+        !this.selection.node.ownerDocument ||
-+        !this.selection.node.ownerDocument.defaultView) {
-+      return;
-+    }
-+
-     let canHiglightNode = this.selection.isNode() &&
-                           this.selection.isConnected() &&
-                           this.selection.isElementNode();
- 
-     if (!canHiglightNode)
-       return;
- 
-     let clientRect = this.selection.node.getBoundingClientRect();
 diff --git a/browser/devtools/inspector/inspector-panel.js b/browser/devtools/inspector/inspector-panel.js
 --- a/browser/devtools/inspector/inspector-panel.js
 +++ b/browser/devtools/inspector/inspector-panel.js
-@@ -15,16 +15,18 @@ let {CssLogic} = require("devtools/style
- require("devtools/inspector/breadcrumbs");
- loader.lazyGetter(this, "MarkupView", () => require("devtools/markupview/markup-view").MarkupView);
- loader.lazyGetter(this, "Selection", () => require("devtools/inspector/selection").Selection);
- loader.lazyGetter(this, "HTMLBreadcrumbs", () => require("devtools/inspector/breadcrumbs").HTMLBreadcrumbs);
- loader.lazyGetter(this, "Highlighter", () => require("devtools/inspector/highlighter").Highlighter);
- loader.lazyGetter(this, "ToolSidebar", () => require("devtools/framework/sidebar").ToolSidebar);
- loader.lazyGetter(this, "SelectorSearch", () => require("devtools/inspector/selector-search").SelectorSearch);
- 
-+require("devtools/inspector/selection");
-+
- const LAYOUT_CHANGE_TIMER = 250;
- 
- /**
-  * Represents an open instance of the Inspector for a tab.
-  * The inspector controls the highlighter, the breadcrumbs,
-  * the markup view, and the sidebar (computed view, rule view
-  * and layout view).
-  */
-@@ -137,40 +139,50 @@ InspectorPanel.prototype = {
+@@ -136,17 +136,17 @@ InspectorPanel.prototype = {
  
        // All the components are initialized. Let's select a node.
        this._selection.setNodeFront(defaultSelection);
  
        if (this.highlighter) {
          this.highlighter.unlock();
        }
  
@@ -75,70 +27,17 @@ diff --git a/browser/devtools/inspector/
  
        this.emit("ready");
        deferred.resolve(this);
      }.bind(this));
  
      this.setupSearchBox();
      this.setupSidebar();
  
-     return deferred.promise;
-   },
- 
-   /**
-    * Return a promise that will resolve to the default node for selection.
-    */
-   _getDefaultNodeForSelection : function() {
-+    if (this._defaultNode) {
-+      return this._defaultNode;
-+    }
-+    let walker = this.walker;
-     // if available set body node as default selected node
-     // else set documentElement
--    return this.walker.querySelector(this.walker.rootNode, "body").then(front => {
-+    return walker.querySelector(this.walker.rootNode, "body").then(front => {
-       if (front) {
-         return front;
-       }
-       return this.walker.documentElement(this.walker.rootNode);
--    });
-+    }).then(node => {
-+      if (walker !== this.walker) {
-+        promise.reject(null);
-+      }
-+      this._defaultNode = node;
-+      return node;
-+    })
-   },
- 
-   /**
-    * Selection object (read only)
-    */
-   get selection() {
-     return this._selection;
-   },
-@@ -273,16 +285,17 @@ InspectorPanel.prototype = {
- 
-   /**
-    * Reset the inspector on navigate away.
-    */
-   onNavigatedAway: function InspectorPanel_onNavigatedAway(event, payload) {
-     let newWindow = payload._navPayload || payload;
-     this.walker.release().then(null, console.error);
-     this.walker = null;
-+    this._defaultNode = null;
-     this.selection.setNodeFront(null);
-     this.selection.setWalker(null);
-     this._destroyMarkup();
-     this.isDirty = false;
- 
-     this.target.inspector.getWalker().then(walker => {
-       if (this._destroyPromise) {
-         walker.release().then(null, console.error);
-@@ -294,17 +307,17 @@ InspectorPanel.prototype = {
+@@ -293,17 +293,17 @@ InspectorPanel.prototype = {
        this._getDefaultNodeForSelection().then(defaultNode => {
          if (this._destroyPromise) {
            return;
          }
          this.selection.setNodeFront(defaultNode, "navigateaway");
  
          this._initMarkup();
          this.once("markuploaded", () => {
@@ -147,99 +46,17 @@ diff --git a/browser/devtools/inspector/
            this.setupSearchBox();
          });
        });
      });
    },
  
    /**
     * When a new node is selected.
-@@ -334,50 +347,59 @@ InspectorPanel.prototype = {
-   updating: function(name) {
-     if (this._updateProgress && this._updateProgress.node != this.selection.nodeFront) {
-       this.cancelUpdate();
-     }
- 
-     if (!this._updateProgress) {
-       // Start an update in progress.
-       var self = this;
-+      if (!this._updateNumber) {
-+        this._updateNumber = 0;
-+      }
-       this._updateProgress = {
-         node: this.selection.nodeFront,
-         outstanding: new Set(),
-+        serial: this._updateNumber++,
-         checkDone: function() {
-           if (this !== self._updateProgress) {
-             return;
-           }
-           if (this.node !== self.selection.nodeFront) {
-             self.cancelUpdate();
-             return;
-           }
-           if (this.outstanding.size !== 0) {
-             return;
-           }
- 
-           self._updateProgress = null;
-+          dump("EMITTING INSPECTOR-UPDATED: " + this.serial + "\n");
-           self.emit("inspector-updated");
-+          dump("DONE EMITTING\n");
-         },
-       }
-+      dump("STARTING INSPECTOR-UPDATED: " + this._updateProgress.serial + "\n");
-     }
- 
-     let progress = this._updateProgress;
-     let done = function() {
-       progress.outstanding.delete(done);
-       progress.checkDone();
-     };
-     progress.outstanding.add(done);
-     return done;
-   },
- 
-   /**
-    * Cancel notification of inspector updates.
-    */
-   cancelUpdate: function() {
-+    if (this._updateProgress)
-+      dump("CANCELLING: " + this._updateProgress.serial + "\n");
-     this._updateProgress = null;
-   },
- 
-   /**
-    * When a new node is selected, before the selection has changed.
-    */
-   onBeforeNewSelection: function InspectorPanel_onBeforeNewSelection(event,
-                                                                      node) {
-@@ -386,19 +408,20 @@ InspectorPanel.prototype = {
-       this.clearPseudoClasses();
-     }
-   },
- 
-   /**
-    * When a node is deleted, select its parent node.
-    */
-   onDetached: function InspectorPanel_onDetached(event, parentNode) {
-+    dump("DETACHED, SETTING PARENT TO: " + parentNode + "\n");
-     this.cancelLayoutChange();
-     this.breadcrumbs.cutAfter(this.breadcrumbs.indexOf(parentNode));
--    this.selection.setNodeFront(parentNode, "detached");
-+    this.selection.setNodeFront(parentNode ? parentNode : this._defaultNode, "detached");
-   },
- 
-   /**
-    * Destroy the inspector.
-    */
-   destroy: function InspectorPanel__destroy() {
-     if (this._destroyPromise) {
-       return this._destroyPromise;
-@@ -665,27 +688,24 @@ InspectorPanel.prototype = {
+@@ -664,27 +664,24 @@ InspectorPanel.prototype = {
     * Delete the selected node.
     */
    deleteNode: function IUI_deleteNode() {
      if (!this.selection.isNode() ||
           this.selection.isRoot()) {
        return;
      }
  
@@ -260,139 +77,29 @@ diff --git a/browser/devtools/inspector/
      }
    },
  
    /**
     * Schedule a low-priority change event for things like paint
     * and resize.
     */
    scheduleLayoutChange: function Inspector_scheduleLayoutChange()
-diff --git a/browser/devtools/inspector/selection.js b/browser/devtools/inspector/selection.js
---- a/browser/devtools/inspector/selection.js
-+++ b/browser/devtools/inspector/selection.js
-@@ -1,16 +1,17 @@
- /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
- /* vim: set ft=javascript ts=2 et sw=2 tw=80: */
- /* 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/. */
- 
- const {Cu, Ci} = require("chrome");
--let EventEmitter = require("devtools/shared/event-emitter");
-+const EventEmitter = require("devtools/shared/event-emitter");
-+const promise = require("sdk/core/promise");
- 
- /**
-  * API
-  *
-  *   new Selection(walker=null, node=null, track={attributes,detached});
-  *   destroy()
-  *   node (readonly)
-  *   setNode(node, origin="unknown")
-@@ -77,31 +78,32 @@ Selection.prototype = {
-     let detached = false;
-     let parentNode = null;
-     for (let m of mutations) {
-       if (!attributeChange && m.type == "attributes") {
-         attributeChange = true;
-       }
-       if (m.type == "childList") {
-         if (!detached && !this.isConnected()) {
-+          detached = true;
-           parentNode = m.target;
--          detached = true;
-         }
-       }
-       if (m.type == "pseudoClassLock"){
-         pseudoChange = true;
-       }
-     }
- 
-+
-     if (attributeChange)
-       this.emit("attribute-changed");
-     if (pseudoChange)
-       this.emit("pseudoclass");
-     if (detached) {
--      this.emit("detached", parentNode.rawNode());
-+      this.emit("detached", parentNode ? parentNode.rawNode() : null);
-       this.emit("detached-front", parentNode);
-     }
-   },
- 
-   destroy: function SN_destroy() {
-     this.setNode(null);
-     this.setWalker(null);
-   },
-@@ -187,40 +189,47 @@ Selection.prototype = {
- 
-     return true;
-   },
- 
-   isLocal: function SN_nsLocal() {
-     return !!this._node;
-   },
- 
--  isConnected: function SN_isConnected() {
--    let node = this._nodeFront;
-+  _isConnected: function(node) {
-+    if (!node || !node.actorID) {
-+      return false;
-+    }
- 
-     // As long as there are still tools going around
-     // accessing node.rawNode, this needs to stay.
--    if (this._node) {
-+    let rawNode = node.rawNode();
-+    if (rawNode) {
-       try {
-         let doc = this.document;
--        return (doc && doc.defaultView && doc.documentElement.contains(this.node));
-+        return (doc && doc.defaultView && doc.documentElement.contains(rawNode));
-       } catch (e) {
-         // "can't access dead object" error
-         return false;
-       }
-     }
- 
-     while(node) {
-       if (node === this._walker.rootNode) {
-         return true;
-       }
-       node = node.parentNode();
-     };
-     return false;
-   },
- 
-+  isConnected: function SN_isConnected() {
-+    return this._isConnected(this._nodeFront);
-+  },
-+
-   isHTMLNode: function SN_isHTMLNode() {
-     let xhtml_ns = "http://www.w3.org/1999/xhtml";
-     return this.isNode() && this.node.namespaceURI == xhtml_ns;
-   },
- 
-   // Node type
- 
-   isElementNode: function SN_isElementNode() {
 diff --git a/browser/devtools/inspector/test/browser_inspector_bug_817558_delete_node.js b/browser/devtools/inspector/test/browser_inspector_bug_817558_delete_node.js
 --- a/browser/devtools/inspector/test/browser_inspector_bug_817558_delete_node.js
 +++ b/browser/devtools/inspector/test/browser_inspector_bug_817558_delete_node.js
-@@ -22,30 +22,34 @@ function test()
+@@ -22,30 +22,31 @@ function test()
      node = iframe.contentDocument.querySelector("span");
      openInspector(runTests);
    }
  
    function runTests(aInspector)
    {
      inspector = aInspector;
      inspector.selection.setNode(node);
 +    inspector.once("inspector-updated", () => {
-+      dump("----- DONE SETTING NODE INITIALLY\n");
 +      let parentNode = node.parentNode;
 +      parentNode.removeChild(node);
  
 -    let parentNode = node.parentNode;
 -    parentNode.removeChild(node);
 +      let tmp = {};
 +      Cu.import("resource:///modules/devtools/LayoutHelpers.jsm", tmp);
 +      ok(!tmp.LayoutHelpers.isNodeConnected(node), "Node considered as disconnected.");
@@ -400,20 +107,18 @@ diff --git a/browser/devtools/inspector/
 -    let tmp = {};
 -    Cu.import("resource:///modules/devtools/LayoutHelpers.jsm", tmp);
 -    ok(!tmp.LayoutHelpers.isNodeConnected(node), "Node considered as disconnected.");
 -
 -    // Wait for the selection to process the mutation
 -    inspector.walker.on("mutations", () => {
 -      is(inspector.selection.node, parentNode, "parent of selection got selected");
 -      finishUp();
-+      dump("---- WAITING FOR AN UPDATE\n");
 +      // Wait for the inspector to process the mutation
 +      inspector.once("inspector-updated", () => {
-+        dump("----- GOT AN UPDATE\n");
 +        is(inspector.selection.node, parentNode, "parent of selection got selected");
 +        finishUp();
 +      });
      });
 -  }
 +  };
  
    function finishUp() {
@@ -421,36 +126,33 @@ diff --git a/browser/devtools/inspector/
      gBrowser.removeCurrentTab();
      finish();
    }
  }
  
 diff --git a/browser/devtools/inspector/test/browser_inspector_initialization.js b/browser/devtools/inspector/test/browser_inspector_initialization.js
 --- a/browser/devtools/inspector/test/browser_inspector_initialization.js
 +++ b/browser/devtools/inspector/test/browser_inspector_initialization.js
-@@ -67,45 +67,63 @@ function startInspectorTests(toolbox)
+@@ -67,36 +67,47 @@ function startInspectorTests(toolbox)
  
  
  function testHighlighter(node)
  {
    ok(isHighlighting(), "Highlighter is highlighting");
    is(getHighlitNode(), node, "Right node is highlighted");
  }
  
 +let callNo = 0;
  function testMarkupView(node)
  {
-+  dump("--MARKUP VIEW CALL: "  + callNo++ + ", " + node + "\n");
    let i = getActiveInspector();
 -  is(i.markup._selectedContainer.node, node, "Right node is selected in the markup view");
-+  dump("inspector: " + i + "\n");
 +  try {
 +    is(i.markup._selectedContainer.node.rawNode(), node, "Right node is selected in the markup view");
 +  } catch(ex) { console.error(ex); }
-+  dump("done?\n");
  }
  
  function testBreadcrumbs(node)
  {
    let b = getActiveInspector().breadcrumbs;
    let expectedText = b.prettyPrintNodeAsText(getNodeFront(node));
    let button = b.container.querySelector("button[checked=true]");
    ok(button, "A crumbs is checked=true");
@@ -459,44 +161,31 @@ diff --git a/browser/devtools/inspector/
  
  function _clickOnInspectMenuItem(node) {
    document.popupNode = node;
    var contentAreaContextMenu = document.getElementById("contentAreaContextMenu");
    var contextMenu = new nsContextMenu(contentAreaContextMenu);
 -  return contextMenu.inspectNode();
 +  var promise = devtools.require("sdk/core/promise");
 +  var deferred = promise.defer();
-+  dump("__INSPECTING NODE\n");
 +  contextMenu.inspectNode().then(() => {
 +    let i = getActiveInspector();
-+    dump("---------- DONE INSPECTING NODE\n");
 +    i.once("inspector-updated", () => {
-+      dump("--------- INSPECTOR UPDATED\n");
 +      deferred.resolve(undefined);
 +    });
 +  });
 +  return deferred.promise;
  }
  
  function runContextMenuTest()
  {
    salutation = doc.getElementById("salutation");
    _clickOnInspectMenuItem(salutation).then(testInitialNodeIsSelected);
  }
  
- function testInitialNodeIsSelected() {
-+  dump("DONE TESTING HERE\n");
-   testHighlighter(salutation);
-   testMarkupView(salutation);
-   testBreadcrumbs(salutation);
-   inspectNodesFromContextTestWhileOpen();
- }
- 
- function inspectNodesFromContextTestWhileOpen()
- {
 diff --git a/browser/devtools/inspector/test/browser_inspector_menu.js b/browser/devtools/inspector/test/browser_inspector_menu.js
 --- a/browser/devtools/inspector/test/browser_inspector_menu.js
 +++ b/browser/devtools/inspector/test/browser_inspector_menu.js
 @@ -48,31 +48,33 @@ function test() {
  
        checkElementMenuItems();
      });
    }
@@ -556,17 +245,17 @@ diff --git a/browser/devtools/markupview
  
  Cu.import("resource:///modules/devtools/LayoutHelpers.jsm");
  Cu.import("resource://gre/modules/devtools/Templater.jsm");
  Cu.import("resource://gre/modules/Services.jsm");
  
  /**
   * Vocabulary for the purposes of this file:
   *
-@@ -36,35 +37,38 @@ Cu.import("resource://gre/modules/Servic
+@@ -36,35 +37,37 @@ Cu.import("resource://gre/modules/Servic
   * @param Inspector aInspector
   *        The inspector we're watching.
   * @param iframe aFrame
   *        An iframe in which the caller has kindly loaded markup-view.xhtml.
   */
  function MarkupView(aInspector, aFrame, aControllerWindow)
  {
    this._inspector = aInspector;
@@ -575,17 +264,16 @@ diff --git a/browser/devtools/markupview
    this.doc = this._frame.contentDocument;
    this._elt = this.doc.querySelector("#root");
  
    try {
      this.maxChildren = Services.prefs.getIntPref("devtools.markup.pagesize");
    } catch(ex) {
      this.maxChildren = DEFAULT_MAX_CHILDREN;
    }
-+  dump("MAX CHILDREN: " + this.maxChildren + "\n");
  
    this.undo = new UndoStack();
    this.undo.installController(aControllerWindow);
  
    this._containers = new WeakMap();
  
 -  this._observer = new this.doc.defaultView.MutationObserver(this._mutationObserver.bind(this));
 +  this._boundMutationObserver = this._mutationObserver.bind(this);
@@ -597,38 +285,35 @@ diff --git a/browser/devtools/markupview
    this._onNewSelection();
  
    this._boundKeyDown = this._onKeyDown.bind(this);
    this._frame.contentWindow.addEventListener("keydown", this._boundKeyDown, false);
  
    this._boundFocus = this._onFocus.bind(this);
    this._frame.addEventListener("focus", this._boundFocus, false);
  
-@@ -93,35 +97,44 @@ MarkupView.prototype = {
+@@ -93,35 +96,41 @@ MarkupView.prototype = {
      return this._containers.get(aNode);
    },
  
    /**
     * Highlight the inspector selected node.
     */
    _onNewSelection: function MT__onNewSelection()
    {
-+    dump("+++UPDATE\n")
 +    let done = this._inspector.updating("markup-view");
      if (this._inspector.selection.isNode()) {
 -      this.showNode(this._inspector.selection.node, true);
 -      this.markNodeAsSelected(this._inspector.selection.node);
 +      this.showNode(this._inspector.selection.nodeFront, true).then(() => {
 +        this.markNodeAsSelected(this._inspector.selection.nodeFront);
-+        dump("+++DONE\n");
 +        done();
 +      });
      } else {
        this.unmarkSelectedNode();
-+      dump("+++DONE\n");
 +      done();
      }
    },
  
    /**
     * Create a TreeWalker to find the next/previous
     * node for selection.
     */
@@ -645,17 +330,17 @@ diff --git a/browser/devtools/markupview
            return Ci.nsIDOMNodeFilter.FILTER_ACCEPT;
          }
          return Ci.nsIDOMNodeFilter.FILTER_SKIP;
        }
      );
      walker.currentNode = this._selectedContainer.elt;
      return walker;
    },
-@@ -140,46 +153,49 @@ MarkupView.prototype = {
+@@ -140,31 +149,32 @@ MarkupView.prototype = {
      }
  
      switch(aEvent.keyCode) {
        case Ci.nsIDOMKeyEvent.DOM_VK_DELETE:
        case Ci.nsIDOMKeyEvent.DOM_VK_BACK_SPACE:
          this.deleteNode(this._selectedContainer.node);
          break;
        case Ci.nsIDOMKeyEvent.DOM_VK_HOME:
@@ -680,34 +365,17 @@ diff --git a/browser/devtools/markupview
          } else {
            let next = this._selectionWalker().nextNode();
            if (next) {
              this.navigate(next.container);
            }
          }
          break;
        case Ci.nsIDOMKeyEvent.DOM_VK_UP:
-         let prev = this._selectionWalker().previousNode();
-         if (prev) {
-           this.navigate(prev.container);
-         }
-         break;
-       case Ci.nsIDOMKeyEvent.DOM_VK_DOWN:
-+        dump("NAVING DOWN\n");
-         let next = this._selectionWalker().nextNode();
-+        dump("NEXT: " + next + ", " + next.container + "\n");
-         if (next) {
-           this.navigate(next.container);
-         }
-         break;
-       case Ci.nsIDOMKeyEvent.DOM_VK_PAGE_UP: {
-         let walker = this._selectionWalker();
-         let selection = this._selectedContainer;
-         for (let i = 0; i < PAGE_SIZE; i++) {
-@@ -215,16 +231,20 @@ MarkupView.prototype = {
+@@ -215,16 +225,20 @@ MarkupView.prototype = {
    },
  
    /**
     * Delete a node from the DOM.
     * This is an undoable action.
     */
    deleteNode: function MC__deleteNode(aNode)
    {
@@ -718,31 +386,29 @@ diff --git a/browser/devtools/markupview
      let doc = nodeDocument(aNode);
      if (aNode === doc ||
          aNode === doc.documentElement ||
          aNode.nodeType == Ci.nsIDOMNode.DOCUMENT_TYPE_NODE) {
        return;
      }
  
      let parentNode = aNode.parentNode;
-@@ -264,129 +284,131 @@ MarkupView.prototype = {
+@@ -264,129 +278,129 @@ MarkupView.prototype = {
     */
    navigate: function MT__navigate(aContainer, aIgnoreFocus)
    {
      if (!aContainer) {
        return;
      }
  
      let node = aContainer.node;
 -    this.showNode(node, false);
 -
 -    this._inspector.selection.setNode(node, "treepanel");
-+    dump("node: " + node + "\n");
 +    this.markNodeAsSelected(node);
-+    dump("setting node selected\n");
 +    this._inspector.selection.setNodeFront(node, "treepanel");
      // This event won't be fired if the node is the same. But the highlighter
      // need to lock the node if it wasn't.
      this._inspector.selection.emit("new-node");
 +    this._inspector.selection.emit("new-node-front");
  
      if (!aIgnoreFocus) {
        aContainer.focus();
@@ -892,17 +558,17 @@ diff --git a/browser/devtools/markupview
    },
  
    /**
     * Expand the node's children.
     */
    expandNode: function MT_expandNode(aNode)
    {
      let container = this._containers.get(aNode);
-@@ -395,86 +417,96 @@ MarkupView.prototype = {
+@@ -395,45 +409,57 @@ MarkupView.prototype = {
  
    /**
     * Expand the entire tree beneath a container.
     *
     * @param aContainer The container to expand.
     */
    _expandAll: function MT_expandAll(aContainer)
    {
@@ -957,22 +623,21 @@ diff --git a/browser/devtools/markupview
    /**
     * Mark the given node selected.
     */
    markNodeAsSelected: function MT_markNodeAsSelected(aNode)
    {
      let container = this._containers.get(aNode);
      if (this._selectedContainer === container) {
        return false;
-     }
+@@ -441,40 +467,37 @@ MarkupView.prototype = {
      if (this._selectedContainer) {
        this._selectedContainer.selected = false;
      }
      this._selectedContainer = container;
-+    dump("SELECTED CONTAINER IS NOW: " + this._selectedContainer + "\n");
      if (aNode) {
        this._selectedContainer.selected = true;
      }
  
 -    this._ensureSelectionVisible();
 -
      return true;
    },
@@ -1002,17 +667,17 @@ diff --git a/browser/devtools/markupview
    },
  
    /**
     * Unmark selected node (no node selected).
     */
    unmarkSelectedNode: function MT_unmarkSelectedNode()
    {
      if (this._selectedContainer) {
-@@ -489,181 +521,200 @@ MarkupView.prototype = {
+@@ -489,181 +512,199 @@ MarkupView.prototype = {
    nodeChanged: function MT_nodeChanged(aNode)
    {
      if (aNode === this._inspector.selection) {
        this._inspector.change("markupview");
      }
    },
  
    /**
@@ -1308,29 +973,28 @@ diff --git a/browser/devtools/markupview
 +    this._inspector.selection.off("new-node-front", this._boundOnNewSelection);
      delete this._boundOnNewSelection;
  
 +    this.walker.off("mutations", this._boundMutationObserver)
 +    delete this._boundMutationObserver;
 +
      delete this._elt;
  
-+    dump("DESTROYING MARKUP PANEL\n");
      delete this._containers;
 -    this._observer.disconnect();
 -    delete this._observer;
    },
  
    /**
     * Initialize the preview panel.
     */
    _initPreview: function MT_initPreview()
    {
      if (!Services.prefs.getBoolPref("devtools.inspector.markupPreview")) {
-@@ -773,25 +824,22 @@ function MarkupContainer(aMarkupView, aN
+@@ -773,25 +814,22 @@ function MarkupContainer(aMarkupView, aN
  
    // The template will fill the following properties
    this.elt = null;
    this.expander = null;
    this.codeBox = null;
    this.children = null;
    this.markup.template("container", this);
    this.elt.container = this;
@@ -1348,17 +1012,17 @@ diff --git a/browser/devtools/markupview
    }.bind(this));
  
    this.codeBox.insertBefore(this.editor.elt, this.children);
  
    this.editor.elt.addEventListener("mousedown", function(evt) {
      this.markup.navigate(this);
    }.bind(this), false);
  
-@@ -804,20 +852,21 @@ function MarkupContainer(aMarkupView, aN
+@@ -804,20 +842,21 @@ function MarkupContainer(aMarkupView, aN
    }
  
    if (this.editor.closeElt) {
      this.editor.closeElt.addEventListener("mousedown", function(evt) {
        this.markup.navigate(this);
      }.bind(this), false);
      this.codeBox.appendChild(this.editor.closeElt);
    }
@@ -1371,17 +1035,17 @@ diff --git a/browser/devtools/markupview
    /**
     * True if the current node has children.  The MarkupView
     * will set this attribute for the MarkupContainer.
     */
    _hasChildren: false,
  
    get hasChildren() {
      return this._hasChildren;
-@@ -827,16 +876,20 @@ MarkupContainer.prototype = {
+@@ -827,16 +866,20 @@ MarkupContainer.prototype = {
      this._hasChildren = aValue;
      if (aValue) {
        this.expander.style.visibility = "visible";
      } else {
        this.expander.style.visibility = "hidden";
      }
    },
  
@@ -1392,17 +1056,17 @@ diff --git a/browser/devtools/markupview
    /**
     * True if the node has been visually expanded in the tree.
     */
    get expanded() {
      return this.children.hasAttribute("expanded");
    },
  
    set expanded(aValue) {
-@@ -869,16 +922,17 @@ MarkupContainer.prototype = {
+@@ -869,16 +912,17 @@ MarkupContainer.prototype = {
    _selected: false,
  
    get selected() {
      return this._selected;
    },
  
    set selected(aValue) {
      this._selected = aValue;
@@ -1410,17 +1074,17 @@ diff --git a/browser/devtools/markupview
      if (this._selected) {
        this.editor.elt.classList.add("theme-selected");
        if (this.editor.closeElt) {
          this.editor.closeElt.classList.add("theme-selected");
        }
      } else {
        this.editor.elt.classList.remove("theme-selected");
        if (this.editor.closeElt) {
-@@ -912,18 +966,20 @@ MarkupContainer.prototype = {
+@@ -912,18 +956,20 @@ MarkupContainer.prototype = {
  
  /**
   * Dummy container node used for the root document element.
   */
  function RootContainer(aMarkupView, aNode)
  {
    this.doc = aMarkupView.doc;
    this.elt = this.doc.createElement("ul");
@@ -1431,17 +1095,17 @@ diff --git a/browser/devtools/markupview
  }
  
  /**
   * Creates an editor for simple nodes.
   */
  function GenericEditor(aContainer, aNode)
  {
    this.elt = aContainer.doc.createElement("span");
-@@ -953,46 +1009,77 @@ function DoctypeEditor(aContainer, aNode
+@@ -953,46 +999,77 @@ function DoctypeEditor(aContainer, aNode
   *
   * @param MarkupContainer aContainer The container owning this editor.
   * @param DOMNode aNode The node being edited.
   * @param string aTemplate The template id to use to build the editor.
   */
  function TextEditor(aContainer, aNode, aTemplate)
  {
    this.node = aNode;
@@ -1529,17 +1193,17 @@ diff --git a/browser/devtools/markupview
    }
  };
  
  /**
   * Creates an editor for an Element node.
   *
   * @param MarkupContainer aContainer The container owning this editor.
   * @param Element aNode The node being edited.
-@@ -1014,53 +1101,57 @@ function ElementEditor(aContainer, aNode
+@@ -1014,53 +1091,57 @@ function ElementEditor(aContainer, aNode
    this.attrList = null;
    this.newAttr = null;
    this.summaryElt = null;
    this.closeElt = null;
  
    // Create the main editor
    this.template("element", this);
  
@@ -1610,17 +1274,17 @@ diff --git a/browser/devtools/markupview
    let tagName = this.node.nodeName.toLowerCase();
    this.tag.textContent = tagName;
    this.closeTag.textContent = tagName;
  
    this.update();
  }
  
  ElementEditor.prototype = {
-@@ -1113,56 +1204,59 @@ ElementEditor.prototype = {
+@@ -1113,56 +1194,59 @@ ElementEditor.prototype = {
        if (aAttr.name == "id") {
          before = this.attrList.firstChild;
        } else if (aAttr.name == "class") {
          let idNode = this.attrs["id"];
          before = idNode ? idNode.nextSibling : this.attrList.firstChild;
        }
        this.attrList.insertBefore(attr, before);
  
@@ -1708,17 +1372,17 @@ diff --git a/browser/devtools/markupview
  
        this.attrs[aAttr.name] = attr;
      }
  
      name.textContent = aAttr.name;
      val.textContent = aAttr.value;
  
      return attr;
-@@ -1185,17 +1279,17 @@ ElementEditor.prototype = {
+@@ -1185,17 +1269,17 @@ ElementEditor.prototype = {
  
      for (let attr of attrs) {
        let attribute = {
          name: attr.name,
          value: attr.value
        };
        // Create an attribute editor next to the current attribute if needed.
        this._createAttribute(attribute, aAttrNode ? aAttrNode.nextSibling : null);
@@ -1727,17 +1391,17 @@ diff --git a/browser/devtools/markupview
      }
  
      this.undo.endBatch();
    },
  
    /**
     * Helper function for _setAttribute and _removeAttribute,
     * returns a function that puts an attribute back the way it was.
-@@ -1242,187 +1336,93 @@ ElementEditor.prototype = {
+@@ -1242,187 +1326,93 @@ ElementEditor.prototype = {
     * Handler for the new attribute editor.
     */
    _onNewAttribute: function EE_onNewAttribute(aValue, aCommit)
    {
      if (!aValue || !aCommit) {
        return;
      }
  
@@ -2118,17 +1782,17 @@ diff --git a/browser/devtools/markupview
          let attr = editor.newAttr;
          editField(attr, 'src="somefile.html?param1=<a>&param2=&uuml;"bl\'ah"');
        },
        after: function() {
          assertAttributes(doc.querySelector("#node25"), {
            id: "node25",
            src: "somefile.html?param1=&lt;a&gt;&param2=&uuml;&quot;bl&apos;ah"
          });
-@@ -255,50 +254,56 @@ function test() {
+@@ -255,50 +254,54 @@ function test() {
      var target = TargetFactory.forTab(gBrowser.selectedTab);
      gDevTools.showToolbox(target, "inspector").then(function(toolbox) {
        inspector = toolbox.getCurrentPanel();
        startTests();
      });
    }
  
    function startTests() {
@@ -2160,20 +1824,18 @@ diff --git a/browser/devtools/markupview
 +              step.setup();
 +            }
 +            step.before();
 +            info("before execute");
 +            step.execute(function() {
 +              info("after execute");
 +              step.after();
 +              ok(markup.undo.canUndo(), "Should be able to undo.");
-+              dump("------undoing\n");
 +              markup.undo.undo();
 +              inspector.once("markupmutation", () => {
-+                dump("----- done undoing\n");
 +                step.before();
 +                ok(markup.undo.canRedo(), "Should be able to redo.");
 +                markup.undo.redo();
 +                inspector.once("markupmutation", () => {
 +                  step.after();
 +                  info("END " + step.desc);
 +                  nextEditTest();
 +                });
@@ -2205,17 +1867,17 @@ diff --git a/browser/devtools/markupview
    }
  
    function addAttributes() {
      let test = {
        desc: "Add attributes by adding to an existing attribute's entry",
        setup: function() {
          inspector.selection.setNode(doc.querySelector("#node18"));
        },
-@@ -311,17 +316,17 @@ function test() {
+@@ -311,17 +314,17 @@ function test() {
            "No classes in the infobar before edit.");
        },
        execute: function(after) {
          inspector.once("markupmutation", function() {
            // needed because we need to make sure the infobar is updated
            // not just the markupview (which happens in this event loop)
            executeSoon(after);
          });
@@ -2224,17 +1886,17 @@ diff --git a/browser/devtools/markupview
          let attr = editor.attrs["id"].querySelector(".editable");
          editField(attr, attr.textContent + ' class="newclass" style="color:green"');
        },
        after: function() {
          assertAttributes(doc.querySelector("#node18"), {
            id: "node18",
            class: "newclass",
            style: "color:green"
-@@ -336,34 +341,34 @@ function test() {
+@@ -336,34 +339,34 @@ function test() {
    function editTagName() {
      let test =  {
        desc: "Edit the tag name",
        setup: function() {
          inspector.selection.setNode(doc.querySelector("#retag-me"));
        },
        before: function() {
          let node = doc.querySelector("#retag-me");
@@ -2262,17 +1924,17 @@ diff --git a/browser/devtools/markupview
          is(node.tagName, "P", "retag-me should be a p.");
          ok(container.selected, "retag-me should be selected.");
          ok(container.expanded, "retag-me should be expanded.");
          is(doc.querySelector("#retag-me-2").parentNode, node,
            "retag-me-2 should be a child of the new element.");
        }
      };
      testAsyncSetup(test, removeElementWithDelete);
-@@ -387,49 +392,51 @@ function test() {
+@@ -387,49 +390,51 @@ function test() {
      };
      testAsyncExecute(test, finishUp);
    }
  
    function testAsyncExecute(test, callback) {
      info("START " + test.desc);
  
      test.before();
@@ -2344,17 +2006,17 @@ diff --git a/browser/devtools/markupview
  function test() {
    waitForExplicitFinish();
  
    // Will hold the doc we're viewing
    let contentTab;
    let doc;
  
    // Holds the MarkupTool object we're testing.
-@@ -40,34 +44,39 @@ function test() {
+@@ -40,20 +44,23 @@ function test() {
          node.parentNode.removeChild(node);
        }
      }
    }
  
    // Verify that the markup in the tool is the same as the markup in the document.
    function checkMarkup()
    {
@@ -2370,33 +2032,17 @@ diff --git a/browser/devtools/markupview
      let parseNode = parseDoc.querySelector("body");
  
      // Grab the text from the markup panel...
      let sel = panelNode.ownerDocument.defaultView.getSelection();
      sel.selectAllChildren(panelNode);
  
      // Parse it
      parseNode.outerHTML = sel;
-     parseNode = parseDoc.querySelector("body");
- 
-     // Pull whitespace out of text and comment nodes, there will
-     // be minor unimportant differences.
-     stripWhitespace(parseNode);
- 
-+    dump("comparing:\n" + parseNode.outerHTML + "\nto:\n" + contentNode.outerHTML + "\n");
-+
-     ok(contentNode.isEqualNode(parseNode), "Markup panel should match document.");
-   }
- 
-   // All the mutation types we want to test.
-   let mutations = [
-     // Add an attribute
-     function() {
-       let node1 = doc.querySelector("#node1");
-@@ -149,30 +158,32 @@ function test() {
+@@ -149,30 +156,32 @@ function test() {
      gDevTools.showToolbox(target, "inspector").then(function(toolbox) {
        inspector = toolbox.getCurrentPanel();
        startTests();
      });
    }
  
    function startTests() {
      markup = inspector.markup;
@@ -2530,17 +2176,17 @@ diff --git a/browser/devtools/markupview
        desc: "Select the first item",
        selector: "#a",
        before: function() {
        },
        after: function() {
          assertChildren("abcde*more*");
        }
      },
-@@ -92,55 +100,50 @@ function test() {
+@@ -92,55 +100,48 @@ function test() {
      doc = content.document;
      waitForFocus(setupTest, content);
    }, true);
    content.location = "http://mochi.test:8888/browser/browser/devtools/markupview/test/browser_inspector_markup_subset.html";
  
    function setupTest() {
      var target = TargetFactory.forTab(gBrowser.selectedTab);
      let toolbox = gDevTools.showToolbox(target, "inspector").then(function(toolbox) {
@@ -2553,23 +2199,21 @@ diff --git a/browser/devtools/markupview
 -  }
 -
 -  function runTests() {
 -    inspector.selection.once("new-node", startTests);
 -    executeSoon(function() {
 -      inspector.selection.setNode(doc.body);
 +      inspector = toolbox.getCurrentPanel();
 +      markup = inspector.markup;
-+      dump("\n\n\n\n\nINSPECTOR READY\n\n\n\n");
 +      inspector.once("inspector-updated", runNextSelection);
      });
    }
  
    function runNextSelection() {
-+    dump("\n\n\n\n\n\nRUN NEXT SELECTION?\n\n\n\n\n");
      let selection = selections.shift();
      if (!selection) {
        clickMore();
        return;
      }
  
      info(selection.desc);
      selection.before();
@@ -2600,517 +2244,53 @@ diff --git a/browser/devtools/markupview
      doc = inspector = null;
      gBrowser.removeCurrentTab();
      finish();
    }
  }
 diff --git a/browser/devtools/markupview/test/head.js b/browser/devtools/markupview/test/head.js
 --- a/browser/devtools/markupview/test/head.js
 +++ b/browser/devtools/markupview/test/head.js
-@@ -11,8 +11,21 @@ let TargetFactory = devtools.TargetFacto
+@@ -11,8 +11,44 @@ let TargetFactory = devtools.TargetFacto
  function clearUserPrefs()
  {
    Services.prefs.clearUserPref("devtools.inspector.htmlPanelOpen");
    Services.prefs.clearUserPref("devtools.inspector.sidebarOpen");
    Services.prefs.clearUserPref("devtools.inspector.activeSidebar");
  }
  
  registerCleanupFunction(clearUserPrefs);
 +
 +Services.prefs.setBoolPref("devtools.debugger.log", true);
 +SimpleTest.registerCleanupFunction(() => {
 +  Services.prefs.clearUserPref("devtools.debugger.log");
 +});
 +
 +function getContainerForRawNode(markupView, rawNode) {
 +  let front = markupView.walker.frontForRawNode(rawNode);
-+  dump("front: " + front + "\n");
 +  let container = markupView.getContainer(front);
 +  return container;
 +}
 +
-diff --git a/browser/devtools/shared/LayoutHelpers.jsm b/browser/devtools/shared/LayoutHelpers.jsm
---- a/browser/devtools/shared/LayoutHelpers.jsm
-+++ b/browser/devtools/shared/LayoutHelpers.jsm
-@@ -37,17 +37,17 @@ this.LayoutHelpers = LayoutHelpers = {
-     // 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) {
--
-+      Cu.import("resource://gre/modules/devtools/Console.jsm", {}).console.trace();
-       // 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);
-diff --git a/browser/devtools/shared/inplace-editor.js b/browser/devtools/shared/inplace-editor.js
---- a/browser/devtools/shared/inplace-editor.js
-+++ b/browser/devtools/shared/inplace-editor.js
-@@ -398,17 +398,17 @@ InplaceEditor.prototype = {
-             --selStart;
-           }
-         }
-       }
-       return this._incrementGenericValue(value, increment, selStart, selEnd, info);
-     }
- 
-     if (incrementedValue === null) {
--      return;
-+      return undefined;
-     }
- 
-     let preRawValue = value.substr(0, range.start);
-     let postRawValue = value.substr(range.end);
- 
-     return {
-       value: preRawValue + incrementedValue + postRawValue,
-       start: range.start + selection[0],
-@@ -435,17 +435,17 @@ InplaceEditor.prototype = {
-     while ((m = reSplitCSS.exec(value)) &&
-           (m.index + m[0].length < offset)) {
-       value = value.substr(m.index + m[0].length);
-       start += m.index + m[0].length;
-       offset -= m.index + m[0].length;
-     }
- 
-     if (!m) {
--      return;
-+      return undefined;
-     }
- 
-     let type;
-     if (m[1]) {
-       type = "url";
-     } else if (m[2]) {
-       type = "rgb";
-     } else if (m[3]) {
-@@ -529,16 +529,17 @@ InplaceEditor.prototype = {
-       if (mid !== null) {
-         return {
-           value: first + mid + last,
-           start: start,
-           end: start + mid.length
-         };
-       }
-     }
-+    return undefined;
-   },
- 
-   /**
-    * Increment the property value for numbers.
-    *
-    * @param {string} rawValue
-    *        Raw value to increment.
-    * @param {number} increment
-@@ -587,20 +588,20 @@ InplaceEditor.prototype = {
-    *        Ending index of the property value.
-    * @return {object} object with properties 'value' and 'selection'.
-    */
-   _incHexColor:
-   function InplaceEditor_incHexColor(rawValue, increment, offset, offsetEnd)
-   {
-     // Return early if no part of the rawValue is selected.
-     if (offsetEnd > rawValue.length && offset >= rawValue.length) {
--      return;
-+      return undefined;
-     }
-     if (offset < 1 && offsetEnd <= 1) {
--      return;
-+      return undefined;
-     }
-     // Ignore the leading #.
-     rawValue = rawValue.substr(1);
-     --offset;
-     --offsetEnd;
- 
-     // Clamp the selection to within the actual value.
-     offset = Math.max(offset, 0);
-@@ -612,17 +613,17 @@ InplaceEditor.prototype = {
-       rawValue = rawValue.charAt(0) + rawValue.charAt(0) +
-                  rawValue.charAt(1) + rawValue.charAt(1) +
-                  rawValue.charAt(2) + rawValue.charAt(2);
-       offset *= 2;
-       offsetEnd *= 2;
-     }
- 
-     if (rawValue.length !== 6) {
--      return;
-+      return undefined;
-     }
- 
-     // If no selection, increment an adjacent color, preferably one to the left.
-     if (offset === offsetEnd) {
-       if (offset === 0) {
-         offsetEnd = 1;
-       } else {
-         offset = offsetEnd - 1;
-@@ -644,17 +645,17 @@ InplaceEditor.prototype = {
-     let isUpper = (rawValue.toUpperCase() === rawValue);
- 
-     for (let pos = offset; pos < offsetEnd; pos += 2) {
-       // Increment the part in [pos, pos+2).
-       let mid = rawValue.substr(pos, 2);
-       let value = parseInt(mid, 16);
- 
-       if (isNaN(value)) {
--        return;
-+        return undefined;
-       }
- 
-       mid = Math.min(Math.max(value + increment, 0), 255).toString(16);
- 
-       while (mid.length < 2) {
-         mid = "0" + mid;
-       }
-       if (isUpper) {
-@@ -671,17 +672,17 @@ InplaceEditor.prototype = {
-   },
- 
-   /**
-    * Call the client's done handler and clear out.
-    */
-   _apply: function InplaceEditor_apply(aEvent)
-   {
-     if (this._applied) {
--      return;
-+      return null;
-     }
- 
-     this._applied = true;
- 
-     if (this.done) {
-       let val = this.input.value.trim();
-       return this.done(this.cancelled ? this.initial : val, !this.cancelled);
-     }
-diff --git a/browser/devtools/shared/theme-switching.js b/browser/devtools/shared/theme-switching.js
---- a/browser/devtools/shared/theme-switching.js
-+++ b/browser/devtools/shared/theme-switching.js
-@@ -21,34 +21,34 @@
-   function switchTheme(newTheme, oldTheme) {
-     let winUtils = window.QueryInterface(Ci.nsIInterfaceRequestor)
-                          .getInterface(Ci.nsIDOMWindowUtils);
- 
-     if (oldTheme && newTheme != oldTheme) {
-       let oldThemeUrl = Services.io.newURI(
-         DEVTOOLS_SKIN_URL + oldTheme + "-theme.css", null, null);
-       try {
--        winUtils.removeSheet(oldThemeUrl, window.AUTHOR_SHEET);
-+        winUtils.removeSheet(oldThemeUrl, Ci.nsIDOMWindowUtils.AUTHOR_SHEET);
-       } catch(ex) {}
-     }
- 
-     let newThemeUrl = Services.io.newURI(
-       DEVTOOLS_SKIN_URL + newTheme + "-theme.css", null, null);
--    winUtils.loadSheet(newThemeUrl, window.AUTHOR_SHEET);
-+    winUtils.loadSheet(newThemeUrl, Ci.nsIDOMWindowUtils.AUTHOR_SHEET);
- 
-     // Floating scrollbars à la osx
-     if (Services.appinfo.OS != "Darwin") {
-       let scrollbarsUrl = Services.io.newURI(
-         DEVTOOLS_SKIN_URL + "floating-scrollbars-light.css", null, null);
- 
-       if (newTheme == "dark") {
--        winUtils.loadSheet(scrollbarsUrl, window.AGENT_SHEET);
-+        winUtils.loadSheet(scrollbarsUrl, Ci.nsIDOMWindowUtils.AGENT_SHEET);
-       } else if (oldTheme == "dark") {
-         try {
--          winUtils.removeSheet(scrollbarsUrl, window.AGENT_SHEET);
-+          winUtils.removeSheet(scrollbarsUrl, Ci.nsIDOMWindowUtils.AGENT_SHEET);
-         } catch(ex) {}
-       }
-       forceStyle();
-     }
- 
-     document.documentElement.classList.remove("theme-" + oldTheme);
-     document.documentElement.classList.add("theme-" + newTheme);
-   }
-diff --git a/browser/devtools/shared/undo.js b/browser/devtools/shared/undo.js
---- a/browser/devtools/shared/undo.js
-+++ b/browser/devtools/shared/undo.js
-@@ -195,12 +195,13 @@ UndoStack.prototype = {
-   },
- 
-   doCommand: function Undo_doCommand(aCommand)
-   {
-     switch(aCommand) {
-       case "cmd_undo": return this.undo();
-       case "cmd_redo": return this.redo();
-     }
-+    return undefined;
-   },
- 
-   onEvent: function Undo_onEvent(aEvent) {},
- }
-diff --git a/browser/devtools/styleinspector/rule-view.js b/browser/devtools/styleinspector/rule-view.js
---- a/browser/devtools/styleinspector/rule-view.js
-+++ b/browser/devtools/styleinspector/rule-view.js
-@@ -209,16 +209,17 @@ ElementStyle.prototype = {
-     }
- 
-     // Ignore inherited rules with no properties.
-     if (aOptions.inherited && rule.textProps.length == 0) {
-       return false;
-     }
- 
-     this.rules.push(rule);
-+    return true;
-   },
- 
-   /**
-    * Mark the properties listed in this.rules with an overridden flag
-    * if an earlier property overrides it.
-    */
-   markOverridden: function ElementStyle_markOverridden()
-   {
-diff --git a/toolkit/devtools/Console.jsm b/toolkit/devtools/Console.jsm
---- a/toolkit/devtools/Console.jsm
-+++ b/toolkit/devtools/Console.jsm
-@@ -69,17 +69,17 @@ function fmt(aStr, aMaxLen, aMinLen, aOp
-       let end = aStr.substring((aStr.length - (aMaxLen / 2)) + 1);
-       return start + "_" + end;
-     }
-     else {
-       return aStr.substring(0, aMaxLen - 1) + "_";
-     }
-   }
-   if (aStr.length < aMinLen) {
--    return Array(aMinLen - aStr.length + 1).join(" ") + aStr;
-+    return aStr + Array(aMinLen - aStr.length + 1).join(" ");
-   }
-   return aStr;
- }
- 
- /**
-  * Utility to extract the constructor name of an object.
-  * Object.toString gives: "[object ?????]"; we want the "?????".
-  *
-diff --git a/toolkit/devtools/server/actors/inspector.js b/toolkit/devtools/server/actors/inspector.js
---- a/toolkit/devtools/server/actors/inspector.js
-+++ b/toolkit/devtools/server/actors/inspector.js
-@@ -122,23 +122,33 @@ var NodeActor = protocol.ActorClass({
-    * from its associated walker.
-    */
-   get conn() this.walker.conn,
- 
-   // Returns the JSON representation of this object over the wire.
-   form: function(detail) {
-     let parentNode = this.walker.parentNode(this);
- 
-+    // Estimate the number of children.
-+    let numChildren = this.rawNode.childNodes.length;
-+    if (numChildren === 0) {
-+      // This might be an iframe with virtual children.
-+      let walker = documentWalker(this.rawNode);
-+      if (walker.firstChild()) {
-+        numChildren = 1;
-+      }
-+    }
++
++Services.prefs.setBoolPref("devtools.debugger.log", true);
++SimpleTest.registerCleanupFunction(() => {
++  Services.prefs.clearUserPref("devtools.debugger.log");
++});
++
++function getContainerForRawNode(markupView, rawNode) {
++  let front = markupView.walker.frontForRawNode(rawNode);
++  let container = markupView.getContainer(front);
++  return container;
++}
 +
-     let form = {
-       actor: this.actorID,
-       parent: parentNode ? parentNode.actorID : undefined,
-       nodeType: this.rawNode.nodeType,
-       namespaceURI: this.namespaceURI,
-       nodeName: this.rawNode.nodeName,
--      numChildren: this.rawNode.childNodes.length,
-+      numChildren: numChildren,
- 
-       // doctype attributes
-       name: this.rawNode.name,
-       publicId: this.rawNode.publicId,
-       systemId: this.rawNode.systemId,
- 
-       attrs: this.writeAttrs(),
- 
-@@ -430,17 +440,19 @@ let NodeFront = protocol.FrontClass(Node
-    */
-   rawNode: function(rawNode) {
-     if (!this.conn._transport._serverConnection) {
-       console.warn("Tried to use rawNode on a remote connection.");
-       return null;
-     }
-     let actor = this.conn._transport._serverConnection.getActor(this.actorID);
-     if (!actor) {
--      throw new Error("Could not find client side for actor " + this.actorID);
-+      // Can happen if we try to get the raw node for an already-expired
-+      // actor.
-+      return null;
-     }
-     return actor.rawNode;
-   }
- });
- 
- /**
-  * Returned from any call that might return a node that isn't connected to root by
-  * nodes the child has seen, such as querySelector.
-@@ -1464,31 +1476,35 @@ var WalkerActor = protocol.ActorClass({
- 
-   /**
-    * Handles mutations from the DOM mutation observer API.
-    *
-    * @param array[MutationRecord] mutations
-    *    See https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver#MutationRecord
-    */
-   onMutations: function(mutations) {
-+    dump("STARTING MUTATION\n");
-     for (let change of mutations) {
-+      dump("GOT: " + change.type + "\n");
-       let targetActor = this._refMap.get(change.target);
-       if (!targetActor) {
-         continue;
-       }
-       let targetNode = change.target;
-       let mutation = {
-         type: change.type,
-         target: targetActor.actorID,
-       }
- 
-       if (mutation.type === "attributes") {
-         mutation.attributeName = change.attributeName;
-         mutation.attributeNamespace = change.attributeNamespace || undefined;
-         mutation.newValue = targetNode.getAttribute(mutation.attributeName);
-+        dump("\tname: " + mutation.attributeName + "\n");
-+        dump("\tnewValue: " + mutation.newValue + "\n")
-       } else if (mutation.type === "characterData") {
-         if (targetNode.nodeValue.length > gValueSummaryLength) {
-           mutation.newValue = targetNode.nodeValue.substring(0, gValueSummaryLength);
-           mutation.incompleteValue = true;
-         } else {
-           mutation.newValue = targetNode.nodeValue;
-         }
-       } else if (mutation.type === "childList") {
-@@ -1522,16 +1538,17 @@ var WalkerActor = protocol.ActorClass({
-           addedActors.push(addedActor.actorID);
-         }
-         mutation.numChildren = change.target.childNodes.length;
-         mutation.removed = removedActors;
-         mutation.added = addedActors;
-       }
-       this.queueMutation(mutation);
-     }
-+    dump("DONE WITH MUTATIONS\n");
-   },
- 
-   onFrameLoad: function(window) {
-     let frame = window.frameElement;
-     let frameActor = this._refMap.get(frame);
-     if (!frameActor) {
-       return;
-     }
-@@ -1552,16 +1569,17 @@ var WalkerActor = protocol.ActorClass({
-         return true;
-       }
-       win = win.frameElement;
-     }
-     return false;
-   },
- 
-   onFrameUnload: function(window) {
-+    dump("------UNLOADING FRAME\n");
-     // Any retained orphans that belong to this document
-     // or its children need to be released, and a mutation sent
-     // to notify of that.
-     let releasedOrphans = [];
- 
-     for (let retained of this._retainedOrphans) {
-       if (Cu.isDeadWrapper(retained.rawNode) ||
-           this._childOfWindow(window, retained.rawNode)) {
-@@ -1759,16 +1777,20 @@ var WalkerFront = exports.WalkerFront = 
-             removedFronts.push(removedFront);
-           }
-           for (let added of change.added) {
-             let addedFront = this.get(added);
-             if (!addedFront) {
-               console.error("Got an addition of an actor we didn't know about: " + added);
-               continue;
-             }
-+            dump("ADDING " + addedFront.actorID + " TO " + targetFront.actorID + "\n");
-+            if (this._orphaned.has(addedFront)) {
-+              dump("IT WAS AN ORPHAN\n");
-+            }
-             addedFront.reparent(targetFront)
- 
-             // The actor is reconnected to the ownership tree, unorphan
-             // it.
-             this._orphaned.delete(addedFront);
-             addedFronts.push(addedFront);
-           }
-           // Before passing to users, replace the added and removed actor
-@@ -1784,16 +1806,17 @@ var WalkerFront = exports.WalkerFront = 
-             if (child.nodeType === Ci.nsIDOMNode.DOCUMENT_NODE) {
-               console.trace("Got an unexpected frameLoad in the inspector, please file a bug on bugzilla.mozilla.org!");
-             }
-           }
-         } else if (change.type === "documentUnload") {
-           // We try to give fronts instead of actorIDs, but these fronts need
-           // to be destroyed now.
-           emittedMutation.target = targetFront.actorID;
-+          emittedMutation.targetParent = targetFront.parentNode();
- 
-           // Release the document node and all of its children, even retained.
-           this._releaseFront(targetFront, true);
-         } else if (change.type === "unretained") {
-           // Retained orphans were force-released without the intervention of
-           // client (probably a navigated frame).
-           for (let released of change.nodes) {
-             let releasedFront = this.get(released);
-@@ -1844,20 +1867,31 @@ var WalkerFront = exports.WalkerFront = 
-     let walkerActor = this.conn._transport._serverConnection.getActor(this.actorID);
-     if (!walkerActor) {
-       throw Error("Could not find client side for actor " + this.actorID);
-     }
-     let nodeActor = walkerActor._ref(rawNode);
- 
-     // Pass the node through a read/write pair to create the client side actor.
-     let nodeType = types.getType("domnode");
-+    dump("BEFORE NODE READ\n");
-     let returnNode = nodeType.read(nodeType.write(nodeActor, walkerActor), this);
-+    dump("AFTER NODE READ\n");
-+    let top = returnNode;
-     let extras = walkerActor.parents(nodeActor);
-     for (let extraActor of extras) {
--      nodeType.read(nodeType.write(extraActor, walkerActor), this);
-+      dump("BEFORE PARENT READ\n");
-+      top = nodeType.read(nodeType.write(extraActor, walkerActor), this);
-+      dump("AFTER PARENT READ\n");
-+    }
++
++Services.prefs.setBoolPref("devtools.debugger.log", true);
++SimpleTest.registerCleanupFunction(() => {
++  Services.prefs.clearUserPref("devtools.debugger.log");
++});
 +
-+    if (top !== this.rootNode) {
-+      // Imported an already-orphaned node.
-+      this._orphaned.add(top);
-+      walkerActor._orphaned.add(this.conn._transport._serverConnection.getActor(top.actorID));
-     }
-     return returnNode;
-   }
- });
- 
- /**
-  * Convenience API for building a list of attribute modifications
-  * for the `modifyAttributes` request.
-diff --git a/toolkit/devtools/server/transport.js b/toolkit/devtools/server/transport.js
---- a/toolkit/devtools/server/transport.js
-+++ b/toolkit/devtools/server/transport.js
-@@ -163,16 +163,17 @@ DebuggerTransport.prototype = {
-       let msg = "Error parsing incoming packet: " + packet + " (" + e + " - " + e.stack + ")";
-       if (Cu.reportError) {
-         Cu.reportError(msg);
-       }
-       dump(msg + "\n");
-       return true;
-     }
- 
-+    Cu.import("resource://gre/modules/devtools/Console.jsm", {}).console.trace();
-     dumpn("Got: " + packet);
-     let self = this;
-     Services.tm.currentThread.dispatch(makeInfallible(function() {
-       self.hooks.onPacket(parsed);
-     }, "DebuggerTransport instance's this.hooks.onPacket"), 0);
- 
-     return true;
-   }
++function getContainerForRawNode(markupView, rawNode) {
++  let front = markupView.walker.frontForRawNode(rawNode);
++  let container = markupView.getContainer(front);
++  return container;
++}
++
new file mode 100644
--- /dev/null
+++ b/selection-fixes.diff
@@ -0,0 +1,55 @@
+# HG changeset patch
+# Parent 9fd2eb6f08ea22545582e1ed08f712fada7f5b58
+
+diff --git a/browser/devtools/inspector/selection.js b/browser/devtools/inspector/selection.js
+--- a/browser/devtools/inspector/selection.js
++++ b/browser/devtools/inspector/selection.js
+@@ -91,17 +91,17 @@ Selection.prototype = {
+       }
+     }
+ 
+     if (attributeChange)
+       this.emit("attribute-changed");
+     if (pseudoChange)
+       this.emit("pseudoclass");
+     if (detached) {
+-      this.emit("detached", parentNode.rawNode());
++      this.emit("detached", parentNode ? parentNode.rawNode() : null);
+       this.emit("detached-front", parentNode);
+     }
+   },
+ 
+   destroy: function SN_destroy() {
+     this.setNode(null);
+     this.setWalker(null);
+   },
+@@ -189,23 +189,27 @@ Selection.prototype = {
+   },
+ 
+   isLocal: function SN_nsLocal() {
+     return !!this._node;
+   },
+ 
+   isConnected: function SN_isConnected() {
+     let node = this._nodeFront;
++    if (!node || !node.actorID) {
++      return false;
++    }
+ 
+     // As long as there are still tools going around
+     // accessing node.rawNode, this needs to stay.
+-    if (this._node) {
++    let rawNode = node.rawNode();
++    if (rawNode) {
+       try {
+         let doc = this.document;
+-        return (doc && doc.defaultView && doc.documentElement.contains(this.node));
++        return (doc && doc.defaultView && doc.documentElement.contains(rawNode));
+       } catch (e) {
+         // "can't access dead object" error
+         return false;
+       }
+     }
+ 
+     while(node) {
+       if (node === this._walker.rootNode) {
--- a/series
+++ b/series
@@ -7,14 +7,20 @@ inspector-front-islocal.diff
 inspector-innerhtml.diff
 inspector-set-attributes.diff
 inspector-set-nodevalue.diff
 inspector-remote-target.diff
 inspector-remote-breadcrumbs.diff
 inspector-remote-pseudoclass.diff
 search-box-remote.diff
 remote-markup.diff
+warning-fixes.diff
+inspector-panel-default-node.diff
+highlighter-fix.diff
+selection-fixes.diff
+console-padend.diff
+actor-markup-fixes.diff
 copy-html.diff
 remote-delete-node.diff
 remote-edit-value.diff
 remote-edit-attributes.diff
 inspector-retain-root.diff #+obsolete
 protocol-clientserver-marshallers.diff #+experimental
new file mode 100644
--- /dev/null
+++ b/warning-fixes.diff
@@ -0,0 +1,221 @@
+# HG changeset patch
+# Parent abf0da1d05d621b0bd58c6d028c0b92ae7aef8ef
+diff --git a/browser/devtools/shared/inplace-editor.js b/browser/devtools/shared/inplace-editor.js
+--- a/browser/devtools/shared/inplace-editor.js
++++ b/browser/devtools/shared/inplace-editor.js
+@@ -398,17 +398,17 @@ InplaceEditor.prototype = {
+             --selStart;
+           }
+         }
+       }
+       return this._incrementGenericValue(value, increment, selStart, selEnd, info);
+     }
+ 
+     if (incrementedValue === null) {
+-      return;
++      return undefined;
+     }
+ 
+     let preRawValue = value.substr(0, range.start);
+     let postRawValue = value.substr(range.end);
+ 
+     return {
+       value: preRawValue + incrementedValue + postRawValue,
+       start: range.start + selection[0],
+@@ -435,17 +435,17 @@ InplaceEditor.prototype = {
+     while ((m = reSplitCSS.exec(value)) &&
+           (m.index + m[0].length < offset)) {
+       value = value.substr(m.index + m[0].length);
+       start += m.index + m[0].length;
+       offset -= m.index + m[0].length;
+     }
+ 
+     if (!m) {
+-      return;
++      return undefined;
+     }
+ 
+     let type;
+     if (m[1]) {
+       type = "url";
+     } else if (m[2]) {
+       type = "rgb";
+     } else if (m[3]) {
+@@ -529,16 +529,17 @@ InplaceEditor.prototype = {
+       if (mid !== null) {
+         return {
+           value: first + mid + last,
+           start: start,
+           end: start + mid.length
+         };
+       }
+     }
++    return undefined;
+   },
+ 
+   /**
+    * Increment the property value for numbers.
+    *
+    * @param {string} rawValue
+    *        Raw value to increment.
+    * @param {number} increment
+@@ -587,20 +588,20 @@ InplaceEditor.prototype = {
+    *        Ending index of the property value.
+    * @return {object} object with properties 'value' and 'selection'.
+    */
+   _incHexColor:
+   function InplaceEditor_incHexColor(rawValue, increment, offset, offsetEnd)
+   {
+     // Return early if no part of the rawValue is selected.
+     if (offsetEnd > rawValue.length && offset >= rawValue.length) {
+-      return;
++      return undefined;
+     }
+     if (offset < 1 && offsetEnd <= 1) {
+-      return;
++      return undefined;
+     }
+     // Ignore the leading #.
+     rawValue = rawValue.substr(1);
+     --offset;
+     --offsetEnd;
+ 
+     // Clamp the selection to within the actual value.
+     offset = Math.max(offset, 0);
+@@ -612,17 +613,17 @@ InplaceEditor.prototype = {
+       rawValue = rawValue.charAt(0) + rawValue.charAt(0) +
+                  rawValue.charAt(1) + rawValue.charAt(1) +
+                  rawValue.charAt(2) + rawValue.charAt(2);
+       offset *= 2;
+       offsetEnd *= 2;
+     }
+ 
+     if (rawValue.length !== 6) {
+-      return;
++      return undefined;
+     }
+ 
+     // If no selection, increment an adjacent color, preferably one to the left.
+     if (offset === offsetEnd) {
+       if (offset === 0) {
+         offsetEnd = 1;
+       } else {
+         offset = offsetEnd - 1;
+@@ -644,17 +645,17 @@ InplaceEditor.prototype = {
+     let isUpper = (rawValue.toUpperCase() === rawValue);
+ 
+     for (let pos = offset; pos < offsetEnd; pos += 2) {
+       // Increment the part in [pos, pos+2).
+       let mid = rawValue.substr(pos, 2);
+       let value = parseInt(mid, 16);
+ 
+       if (isNaN(value)) {
+-        return;
++        return undefined;
+       }
+ 
+       mid = Math.min(Math.max(value + increment, 0), 255).toString(16);
+ 
+       while (mid.length < 2) {
+         mid = "0" + mid;
+       }
+       if (isUpper) {
+@@ -671,17 +672,17 @@ InplaceEditor.prototype = {
+   },
+ 
+   /**
+    * Call the client's done handler and clear out.
+    */
+   _apply: function InplaceEditor_apply(aEvent)
+   {
+     if (this._applied) {
+-      return;
++      return null;
+     }
+ 
+     this._applied = true;
+ 
+     if (this.done) {
+       let val = this.input.value.trim();
+       return this.done(this.cancelled ? this.initial : val, !this.cancelled);
+     }
+diff --git a/browser/devtools/shared/theme-switching.js b/browser/devtools/shared/theme-switching.js
+--- a/browser/devtools/shared/theme-switching.js
++++ b/browser/devtools/shared/theme-switching.js
+@@ -21,34 +21,34 @@
+   function switchTheme(newTheme, oldTheme) {
+     let winUtils = window.QueryInterface(Ci.nsIInterfaceRequestor)
+                          .getInterface(Ci.nsIDOMWindowUtils);
+ 
+     if (oldTheme && newTheme != oldTheme) {
+       let oldThemeUrl = Services.io.newURI(
+         DEVTOOLS_SKIN_URL + oldTheme + "-theme.css", null, null);
+       try {
+-        winUtils.removeSheet(oldThemeUrl, window.AUTHOR_SHEET);
++        winUtils.removeSheet(oldThemeUrl, Ci.nsIDOMWindowUtils.AUTHOR_SHEET);
+       } catch(ex) {}
+     }
+ 
+     let newThemeUrl = Services.io.newURI(
+       DEVTOOLS_SKIN_URL + newTheme + "-theme.css", null, null);
+-    winUtils.loadSheet(newThemeUrl, window.AUTHOR_SHEET);
++    winUtils.loadSheet(newThemeUrl, Ci.nsIDOMWindowUtils.AUTHOR_SHEET);
+ 
+     // Floating scrollbars à la osx
+     if (Services.appinfo.OS != "Darwin") {
+       let scrollbarsUrl = Services.io.newURI(
+         DEVTOOLS_SKIN_URL + "floating-scrollbars-light.css", null, null);
+ 
+       if (newTheme == "dark") {
+-        winUtils.loadSheet(scrollbarsUrl, window.AGENT_SHEET);
++        winUtils.loadSheet(scrollbarsUrl, Ci.nsIDOMWindowUtils.AGENT_SHEET);
+       } else if (oldTheme == "dark") {
+         try {
+-          winUtils.removeSheet(scrollbarsUrl, window.AGENT_SHEET);
++          winUtils.removeSheet(scrollbarsUrl, Ci.nsIDOMWindowUtils.AGENT_SHEET);
+         } catch(ex) {}
+       }
+       forceStyle();
+     }
+ 
+     document.documentElement.classList.remove("theme-" + oldTheme);
+     document.documentElement.classList.add("theme-" + newTheme);
+   }
+diff --git a/browser/devtools/shared/undo.js b/browser/devtools/shared/undo.js
+--- a/browser/devtools/shared/undo.js
++++ b/browser/devtools/shared/undo.js
+@@ -195,12 +195,13 @@ UndoStack.prototype = {
+   },
+ 
+   doCommand: function Undo_doCommand(aCommand)
+   {
+     switch(aCommand) {
+       case "cmd_undo": return this.undo();
+       case "cmd_redo": return this.redo();
+     }
++    return undefined;
+   },
+ 
+   onEvent: function Undo_onEvent(aEvent) {},
+ }
+diff --git a/browser/devtools/styleinspector/rule-view.js b/browser/devtools/styleinspector/rule-view.js
+--- a/browser/devtools/styleinspector/rule-view.js
++++ b/browser/devtools/styleinspector/rule-view.js
+@@ -209,16 +209,17 @@ ElementStyle.prototype = {
+     }
+ 
+     // Ignore inherited rules with no properties.
+     if (aOptions.inherited && rule.textProps.length == 0) {
+       return false;
+     }
+ 
+     this.rules.push(rule);
++    return true;
+   },
+ 
+   /**
+    * Mark the properties listed in this.rules with an overridden flag
+    * if an earlier property overrides it.
+    */
+   markOverridden: function ElementStyle_markOverridden()
+   {