Bug 1249119 - Fix inspector startup when opening it on a loading document r=jdescottes
authorAlexandre Poirot <poirot.alex@gmail.com>
Wed, 19 Oct 2016 05:25:26 -0700
changeset 428690 f08cf9dc4b927f6fe5cc18070c8b2f9e860de45a
parent 428689 7664d47e1f14521f2b6a020237e4015cd3aacd9b
child 428691 46b32222e682b25578d090664a9c32f389e9dae4
push id33405
push userbcampen@mozilla.com
push dateMon, 24 Oct 2016 15:32:53 +0000
reviewersjdescottes
bugs1249119
milestone52.0a1
Bug 1249119 - Fix inspector startup when opening it on a loading document r=jdescottes MozReview-Commit-ID: 5d4K6VFLTgE
devtools/client/inspector/inspector.js
devtools/server/actors/inspector.js
devtools/shared/fronts/inspector.js
--- a/devtools/client/inspector/inspector.js
+++ b/devtools/client/inspector/inspector.js
@@ -124,17 +124,22 @@ Inspector.prototype = {
   init: Task.async(function* () {
     // Localize all the nodes containing a data-localization attribute.
     localizeMarkup(this.panelDoc);
 
     this._cssPropertiesLoaded = initCssProperties(this.toolbox);
     yield this._cssPropertiesLoaded;
     yield this.target.makeRemote();
     yield this._getPageStyle();
-    let defaultSelection = yield this._getDefaultNodeForSelection();
+
+    // This may throw if the document is still loading and we are
+    // refering to a dead about:blank document
+    let defaultSelection = yield this._getDefaultNodeForSelection()
+      .catch(this._handleRejectionIfNotDestroyed);
+
     return yield this._deferredOpen(defaultSelection);
   }),
 
   get toolbox() {
     return this._toolbox;
   },
 
   get inspector() {
@@ -208,24 +213,24 @@ Inspector.prototype = {
         }).catch(e => console.error(e)),
       ]);
     });
   },
 
   _deferredOpen: function (defaultSelection) {
     let deferred = defer();
 
+    this.breadcrumbs = new HTMLBreadcrumbs(this);
+
     this.walker.on("new-root", this.onNewRoot);
 
     this.selection.on("new-node-front", this.onNewSelection);
     this.selection.on("before-new-node-front", this.onBeforeNewSelection);
     this.selection.on("detached-front", this.onDetached);
 
-    this.breadcrumbs = new HTMLBreadcrumbs(this);
-
     if (this.target.isLocalTab) {
       // Show a warning when the debugger is paused.
       // We show the warning only when the inspector
       // is selected.
       this.updateDebuggerPausedWarning = () => {
         let notificationBox = this._toolbox.getNotificationBox();
         let notification =
           notificationBox.getNotificationWithValue("inspector-script-paused");
@@ -252,18 +257,20 @@ Inspector.prototype = {
 
     this._initMarkup();
     this.isReady = false;
 
     this.once("markuploaded", () => {
       this.isReady = true;
 
       // All the components are initialized. Let's select a node.
-      this.selection.setNodeFront(defaultSelection, "inspector-open");
-      this.markup.expandNode(this.selection.nodeFront);
+      if (defaultSelection) {
+        this.selection.setNodeFront(defaultSelection, "inspector-open");
+        this.markup.expandNode(this.selection.nodeFront);
+      }
 
       // And setup the toolbar only now because it may depend on the document.
       this.setupToolbar();
 
       this.emit("ready");
       deferred.resolve(this);
     });
 
--- a/devtools/server/actors/inspector.js
+++ b/devtools/server/actors/inspector.js
@@ -2349,17 +2349,23 @@ var WalkerActor = protocol.ActorClassWit
       type: "inlineTextChild",
       target: parentActor.actorID,
       inlineTextChild:
         inlineTextChild ? inlineTextChild.form() : undefined
     });
   },
 
   onFrameLoad: function ({ window, isTopLevel }) {
-    if (!this.rootDoc && isTopLevel) {
+    if (isTopLevel) {
+      // If we initialize the inspector while the document is loading,
+      // we may already have a root document set in the constructor.
+      if (this.rootDoc && !Cu.isDeadWrapper(this.rootDoc) &&
+          this.rootDoc.defaultView) {
+        this.onFrameUnload({ window: this.rootDoc.defaultView });
+      }
       this.rootDoc = window.document;
       this.rootNode = this.document();
       this.queueMutation({
         type: "newRoot",
         target: this.rootNode.form()
       });
       return;
     }
--- a/devtools/shared/fronts/inspector.js
+++ b/devtools/shared/fronts/inspector.js
@@ -746,16 +746,21 @@ const WalkerFront = FrontClassWithSpec(w
     return this._getMutations(options).then(mutations => {
       let emitMutations = [];
       for (let change of mutations) {
         // The target is only an actorID, get the associated front.
         let targetID;
         let targetFront;
 
         if (change.type === "newRoot") {
+          // We may receive a new root without receiving any documentUnload
+          // beforehand. Like when opening tools in middle of a document load.
+          if (this.rootNode) {
+            this._createRootNodePromise();
+          }
           this.rootNode = types.getType("domnode").read(change.target, this);
           this._rootNodeDeferred.resolve(this.rootNode);
           targetID = this.rootNode.actorID;
           targetFront = this.rootNode;
         } else {
           targetID = change.target;
           targetFront = this.get(targetID);
         }