Bug 1259743 - Part 1: Inline sources in iframe stop being displayed after few reloads. r=ochameau
authorJarda Snajdr <jsnajdr@gmail.com>
Thu, 28 Apr 2016 03:53:00 -0400
changeset 295518 bb1df86bbb354397a6dc861bbb412e346185692e
parent 295517 4dc48f3688f053e2fa74bf6c7beb4dff274ffc1f
child 295519 f0222c4acdfa113eb559e344c457e8c6dc79882a
push id75951
push userkwierso@gmail.com
push dateFri, 29 Apr 2016 23:01:24 +0000
treeherdermozilla-inbound@f8896b71e9bc [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersochameau
bugs1259743
milestone49.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1259743 - Part 1: Inline sources in iframe stop being displayed after few reloads. r=ochameau
devtools/client/debugger/test/mochitest/browser.ini
devtools/client/debugger/test/mochitest/browser_dbg_sources-iframe-reload.js
devtools/server/actors/webbrowser.js
--- a/devtools/client/debugger/test/mochitest/browser.ini
+++ b/devtools/client/debugger/test/mochitest/browser.ini
@@ -456,16 +456,17 @@ skip-if = e10s && debug
 skip-if = e10s # Bug 1093535
 [browser_dbg_sources-cache.js]
 [browser_dbg_sources-contextmenu-01.js]
 [browser_dbg_sources-contextmenu-02.js]
 skip-if = e10s && debug
 [browser_dbg_sources-eval-01.js]
 skip-if = true # non-named eval sources turned off for now, bug 1124106
 [browser_dbg_sources-eval-02.js]
+[browser_dbg_sources-iframe-reload.js]
 [browser_dbg_sources-keybindings.js]
 skip-if = e10s && debug
 [browser_dbg_sources-labels.js]
 skip-if = e10s && debug
 [browser_dbg_sources-large.js]
 [browser_dbg_sources-sorting.js]
 skip-if = e10s && debug
 [browser_dbg_sources-bookmarklet.js]
new file mode 100644
--- /dev/null
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_sources-iframe-reload.js
@@ -0,0 +1,35 @@
+/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
+/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+/**
+ * Make sure iframe scripts don't disappear after few reloads (bug 1259743)
+ */
+
+"use strict";
+
+const IFRAME_URL = "data:text/html;charset=utf-8," +
+  "<script>function fn() { console.log('hello'); }</script>" +
+  "<div onclick='fn()'>hello</div>";
+const TAB_URL = `data:text/html;charset=utf-8,<iframe src="${IFRAME_URL}"/>`;
+
+add_task(function* () {
+  let [,, panel] = yield initDebugger("about:blank");
+  let dbg = panel.panelWin;
+  let newSource;
+
+  newSource = waitForDebuggerEvents(panel, dbg.EVENTS.NEW_SOURCE);
+  reload(panel, TAB_URL);
+  yield newSource;
+  ok(true, "Source event fired on initial load");
+
+  for (let i = 0; i < 5; i++) {
+    newSource = waitForDebuggerEvents(panel, dbg.EVENTS.NEW_SOURCE);
+    reload(panel);
+    yield newSource;
+    ok(true, `Source event fired after ${i + 1} reloads`);
+  }
+
+  yield closeDebuggerAndFinish(panel);
+});
--- a/devtools/server/actors/webbrowser.js
+++ b/devtools/server/actors/webbrowser.js
@@ -1180,23 +1180,23 @@ TabActor.prototype = {
 
   _onDocShellDestroy: function (docShell) {
     let webProgress = docShell.QueryInterface(Ci.nsIInterfaceRequestor)
                               .getInterface(Ci.nsIWebProgress);
     this._notifyDocShellDestroy(webProgress);
   },
 
   _isRootDocShell: function (docShell) {
-    // Root docshells like top level xul windows don't have chromeEventHandler.
-    // Root docshells in child processes have one, it is TabChildGlobal,
-    // which isn't a DOM Element.
-    // Non-root docshell have a chromeEventHandler that is either
-    // xul:iframe, xul:browser or html:iframe.
-    return !docShell.chromeEventHandler ||
-           !(docShell.chromeEventHandler instanceof Ci.nsIDOMElement);
+    // Should report as root docshell:
+    //  - New top level window's docshells, when using ChromeActor against a
+    // process. It allows tracking iframes of the newly opened windows
+    // like Browser console or new browser windows.
+    //  - MozActivities or window.open frames on B2G, where a new root docshell
+    // is spawn in the child process of the app.
+    return !docShell.parent;
   },
 
   // Convert docShell list to windows objects list being sent to the client
   _docShellsToWindows: function (docshells) {
     return docshells.map(docShell => {
       let webProgress = docShell.QueryInterface(Ci.nsIInterfaceRequestor)
                                 .getInterface(Ci.nsIWebProgress);
       let window = webProgress.DOMWindow;
@@ -1242,22 +1242,20 @@ TabActor.prototype = {
     this.conn.send({ from: this.actorID,
                      type: "frameUpdate",
                      frames: [{
                        id: id,
                        destroy: true
                      }]
                    });
 
-    // Stop watching this docshell if it's a root one.
-    // (child processes spawn new root docshells)
+    // Stop watching this docshell (the unwatch() method will check if we
+    // started watching it before).
     webProgress.QueryInterface(Ci.nsIDocShell);
-    if (this._isRootDocShell(webProgress)) {
-      this._progressListener.unwatch(webProgress);
-    }
+    this._progressListener.unwatch(webProgress);
 
     if (webProgress.DOMWindow == this._originalWindow) {
       // If the original top level document we connected to is removed,
       // we try to switch to any other top level document
       let rootDocShells = this.docShells
                               .filter(d => {
                                 return d != this.docShell &&
                                        this._isRootDocShell(d);
@@ -2194,32 +2192,41 @@ function DebuggerProgressListener(aTabAc
 
   // Watch for windows destroyed (global observer that will need filtering)
   Services.obs.addObserver(this, "inner-window-destroyed", false);
 
   // XXX: for now we maintain the list of windows we know about in this instance
   // so that we can discriminate windows we care about when observing
   // inner-window-destroyed events. Bug 1016952 would remove the need for this.
   this._knownWindowIDs = new Map();
+
+  this._watchedDocShells = new WeakSet();
 }
 
 DebuggerProgressListener.prototype = {
   QueryInterface: XPCOMUtils.generateQI([
     Ci.nsIWebProgressListener,
     Ci.nsISupportsWeakReference,
     Ci.nsISupports,
   ]),
 
   destroy: function() {
     Services.obs.removeObserver(this, "inner-window-destroyed", false);
     this._knownWindowIDs.clear();
     this._knownWindowIDs = null;
   },
 
   watch: function(docShell) {
+    // Add the docshell to the watched set. We're actually adding the window,
+    // because docShell objects are not wrappercached and would be rejected
+    // by the WeakSet.
+    let docShellWindow = docShell.QueryInterface(Ci.nsIInterfaceRequestor)
+                                 .getInterface(Ci.nsIDOMWindow);
+    this._watchedDocShells.add(docShellWindow);
+
     let webProgress = docShell.QueryInterface(Ci.nsIInterfaceRequestor)
                               .getInterface(Ci.nsIWebProgress);
     webProgress.addProgressListener(this, Ci.nsIWebProgress.NOTIFY_STATUS |
                                           Ci.nsIWebProgress.NOTIFY_STATE_WINDOW |
                                           Ci.nsIWebProgress.NOTIFY_STATE_DOCUMENT);
 
     let handler = getDocShellChromeEventHandler(docShell);
     handler.addEventListener("DOMWindowCreated", this._onWindowCreated, true);
@@ -2229,16 +2236,22 @@ DebuggerProgressListener.prototype = {
     // Dispatch the _windowReady event on the tabActor for pre-existing windows
     for (let win of this._getWindowsInDocShell(docShell)) {
       this._tabActor._windowReady(win);
       this._knownWindowIDs.set(getWindowID(win), win);
     }
   },
 
   unwatch: function(docShell) {
+    let docShellWindow = docShell.QueryInterface(Ci.nsIInterfaceRequestor)
+                                 .getInterface(Ci.nsIDOMWindow);
+    if (!this._watchedDocShells.has(docShellWindow)) {
+      return;
+    }
+
     let webProgress = docShell.QueryInterface(Ci.nsIInterfaceRequestor)
                               .getInterface(Ci.nsIWebProgress);
     // During process shutdown, the docshell may already be cleaned up and throw
     try {
       webProgress.removeProgressListener(this);
     } catch(e) {}
 
     let handler = getDocShellChromeEventHandler(docShell);