Bug 1172897 - Extract BrowserTabActor to new file. r=ochameau draft
authorJ. Ryan Stinnett <jryans@gmail.com>
Wed, 30 May 2018 18:31:34 -0500
changeset 805434 98c98bb695ef5f1cfbb832af37fc5a0e7276dbe4
parent 805433 59bc2e8c70dc0f7da6bdfbef52cc2647679f077d
child 805435 eb30aa2937344d249dd23ea01b2513c136d0a40f
push id112656
push userbmo:jryans@gmail.com
push dateThu, 07 Jun 2018 20:15:26 +0000
reviewersochameau
bugs1172897
milestone62.0a1
Bug 1172897 - Extract BrowserTabActor to new file. r=ochameau MozReview-Commit-ID: 6bFiakvkla3
devtools/server/actors/browser-tab.js
devtools/server/actors/moz.build
devtools/server/actors/webbrowser.js
new file mode 100644
--- /dev/null
+++ b/devtools/server/actors/browser-tab.js
@@ -0,0 +1,175 @@
+/* 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/. */
+
+"use strict";
+
+const { DebuggerServer } = require("devtools/server/main");
+loader.lazyImporter(this, "PlacesUtils", "resource://gre/modules/PlacesUtils.jsm");
+
+/**
+ * Creates a target actor for handling requests to a single browser frame.
+ * Both <xul:browser> and <iframe mozbrowser> are supported.
+ * This actor is a shim that connects to a FrameTargetActor in a remote browser process.
+ * All RDP packets get forwarded using the message manager.
+ *
+ * @param connection The main RDP connection.
+ * @param browser <xul:browser> or <iframe mozbrowser> element to connect to.
+ * @param options
+ *        - {Boolean} favicons: true if the form should include the favicon for the tab.
+ */
+function BrowserTabActor(connection, browser, options = {}) {
+  this._conn = connection;
+  this._browser = browser;
+  this._form = null;
+  this.exited = false;
+  this.options = options;
+}
+
+BrowserTabActor.prototype = {
+  async connect() {
+    const onDestroy = () => {
+      if (this._deferredUpdate) {
+        // Reject the update promise if the tab was destroyed while requesting an update
+        this._deferredUpdate.reject({
+          error: "tabDestroyed",
+          message: "Tab destroyed while performing a BrowserTabActor update"
+        });
+      }
+      this.exit();
+    };
+    const connect = DebuggerServer.connectToFrame(this._conn, this._browser, onDestroy);
+    const form = await connect;
+
+    this._form = form;
+    if (this.options.favicons) {
+      this._form.favicon = await this.getFaviconData();
+    }
+
+    return this;
+  },
+
+  get _tabbrowser() {
+    if (this._browser && typeof this._browser.getTabBrowser == "function") {
+      return this._browser.getTabBrowser();
+    }
+    return null;
+  },
+
+  get _mm() {
+    // Get messageManager from XUL browser (which might be a specialized tunnel for RDM)
+    // or else fallback to asking the frameLoader itself.
+    return this._browser.messageManager ||
+           this._browser.frameLoader.messageManager;
+  },
+
+  async getFaviconData() {
+    try {
+      const { data } = await PlacesUtils.promiseFaviconData(this._form.url);
+      return data;
+    } catch (e) {
+      // Favicon unavailable for this url.
+      return null;
+    }
+  },
+
+  /**
+   * @param {Object} options
+   *        See BrowserTabActor constructor.
+   */
+  async update(options = {}) {
+    // Update the BrowserTabActor options.
+    this.options = options;
+
+    // If the child happens to be crashed/close/detach, it won't have _form set,
+    // so only request form update if some code is still listening on the other
+    // side.
+    if (this.exited) {
+      return this.connect();
+    }
+
+    const form = await new Promise(resolve => {
+      const onFormUpdate = msg => {
+        // There may be more than one FrameTargetActor up and running
+        if (this._form.actor != msg.json.actor) {
+          return;
+        }
+        this._mm.removeMessageListener("debug:form", onFormUpdate);
+
+        resolve(msg.json);
+      };
+
+      this._mm.addMessageListener("debug:form", onFormUpdate);
+      this._mm.sendAsyncMessage("debug:form");
+    });
+
+    this._form = form;
+    if (this.options.favicons) {
+      this._form.favicon = await this.getFaviconData();
+    }
+
+    return this;
+  },
+
+  /**
+   * If we don't have a title from the content side because it's a zombie tab, try to find
+   * it on the chrome side.
+   */
+  get title() {
+    // On Fennec, we can check the session store data for zombie tabs
+    if (this._browser && this._browser.__SS_restore) {
+      const sessionStore = this._browser.__SS_data;
+      // Get the last selected entry
+      const entry = sessionStore.entries[sessionStore.index - 1];
+      return entry.title;
+    }
+    // If contentTitle is empty (e.g. on a not-yet-restored tab), but there is a
+    // tabbrowser (i.e. desktop Firefox, but not Fennec), we can use the label
+    // as the title.
+    if (this._tabbrowser) {
+      const tab = this._tabbrowser.getTabForBrowser(this._browser);
+      if (tab) {
+        return tab.label;
+      }
+    }
+    return "";
+  },
+
+  /**
+   * If we don't have a url from the content side because it's a zombie tab, try to find
+   * it on the chrome side.
+   */
+  get url() {
+    // On Fennec, we can check the session store data for zombie tabs
+    if (this._browser && this._browser.__SS_restore) {
+      const sessionStore = this._browser.__SS_data;
+      // Get the last selected entry
+      const entry = sessionStore.entries[sessionStore.index - 1];
+      return entry.url;
+    }
+    return null;
+  },
+
+  form() {
+    const form = Object.assign({}, this._form);
+    // In some cases, the title and url fields might be empty.  Zombie tabs (not yet
+    // restored) are a good example.  In such cases, try to look up values for these
+    // fields using other data in the parent process.
+    if (!form.title) {
+      form.title = this.title;
+    }
+    if (!form.url) {
+      form.url = this.url;
+    }
+
+    return form;
+  },
+
+  exit() {
+    this._browser = null;
+    this._form = null;
+    this.exited = true;
+  },
+};
+
+exports.BrowserTabActor = BrowserTabActor;
--- a/devtools/server/actors/moz.build
+++ b/devtools/server/actors/moz.build
@@ -22,16 +22,17 @@ DevToolsModules(
     'actor-registry.js',
     'addon-console.js',
     'addon.js',
     'addons.js',
     'animation-type-longhand.js',
     'animation.js',
     'array-buffer.js',
     'breakpoint.js',
+    'browser-tab.js',
     'call-watcher.js',
     'canvas.js',
     'child-process.js',
     'chrome.js',
     'common.js',
     'css-properties.js',
     'csscoverage.js',
     'device.js',
--- a/devtools/server/actors/webbrowser.js
+++ b/devtools/server/actors/webbrowser.js
@@ -7,23 +7,23 @@
 "use strict";
 
 var { Ci } = require("chrome");
 var Services = require("Services");
 var { DebuggerServer } = require("devtools/server/main");
 var DevToolsUtils = require("devtools/shared/DevToolsUtils");
 
 loader.lazyRequireGetter(this, "RootActor", "devtools/server/actors/root", true);
+loader.lazyRequireGetter(this, "BrowserTabActor", "devtools/server/actors/browser-tab", true);
 loader.lazyRequireGetter(this, "BrowserAddonActor", "devtools/server/actors/addon", true);
 loader.lazyRequireGetter(this, "WebExtensionParentActor", "devtools/server/actors/webextension-parent", true);
 loader.lazyRequireGetter(this, "WorkerActorList", "devtools/server/actors/worker-list", true);
 loader.lazyRequireGetter(this, "ServiceWorkerRegistrationActorList", "devtools/server/actors/worker-list", true);
 loader.lazyRequireGetter(this, "ProcessActorList", "devtools/server/actors/process", true);
 loader.lazyImporter(this, "AddonManager", "resource://gre/modules/AddonManager.jsm");
-loader.lazyImporter(this, "PlacesUtils", "resource://gre/modules/PlacesUtils.jsm");
 
 /**
  * Browser-specific actors.
  */
 
 /**
  * Yield all windows of type |windowType|, from the oldest window to the
  * youngest, using nsIWindowMediator::getEnumerator. We're usually
@@ -684,183 +684,16 @@ DevToolsUtils.makeInfallible(function(wi
         this._handleActorClose(actor, browser);
       }
     }
   }, "BrowserTabList.prototype.onCloseWindow's delayed body"));
 }, "BrowserTabList.prototype.onCloseWindow");
 
 exports.BrowserTabList = BrowserTabList;
 
-/**
- * Creates a target actor for handling requests to a single browser frame.
- * Both <xul:browser> and <iframe mozbrowser> are supported.
- * This actor is a shim that connects to a FrameTargetActor in a remote browser process.
- * All RDP packets get forwarded using the message manager.
- *
- * @param connection The main RDP connection.
- * @param browser <xul:browser> or <iframe mozbrowser> element to connect to.
- * @param options
- *        - {Boolean} favicons: true if the form should include the favicon for the tab.
- */
-function BrowserTabActor(connection, browser, options = {}) {
-  this._conn = connection;
-  this._browser = browser;
-  this._form = null;
-  this.exited = false;
-  this.options = options;
-}
-
-BrowserTabActor.prototype = {
-  async connect() {
-    const onDestroy = () => {
-      if (this._deferredUpdate) {
-        // Reject the update promise if the tab was destroyed while requesting an update
-        this._deferredUpdate.reject({
-          error: "tabDestroyed",
-          message: "Tab destroyed while performing a BrowserTabActor update"
-        });
-      }
-      this.exit();
-    };
-    const connect = DebuggerServer.connectToFrame(this._conn, this._browser, onDestroy);
-    const form = await connect;
-
-    this._form = form;
-    if (this.options.favicons) {
-      this._form.favicon = await this.getFaviconData();
-    }
-
-    return this;
-  },
-
-  get _tabbrowser() {
-    if (this._browser && typeof this._browser.getTabBrowser == "function") {
-      return this._browser.getTabBrowser();
-    }
-    return null;
-  },
-
-  get _mm() {
-    // Get messageManager from XUL browser (which might be a specialized tunnel for RDM)
-    // or else fallback to asking the frameLoader itself.
-    return this._browser.messageManager ||
-           this._browser.frameLoader.messageManager;
-  },
-
-  async getFaviconData() {
-    try {
-      const { data } = await PlacesUtils.promiseFaviconData(this._form.url);
-      return data;
-    } catch (e) {
-      // Favicon unavailable for this url.
-      return null;
-    }
-  },
-
-  /**
-   * @param {Object} options
-   *        See BrowserTabActor constructor.
-   */
-  async update(options = {}) {
-    // Update the BrowserTabActor options.
-    this.options = options;
-
-    // If the child happens to be crashed/close/detach, it won't have _form set,
-    // so only request form update if some code is still listening on the other
-    // side.
-    if (this.exited) {
-      return this.connect();
-    }
-
-    const form = await new Promise(resolve => {
-      const onFormUpdate = msg => {
-        // There may be more than one FrameTargetActor up and running
-        if (this._form.actor != msg.json.actor) {
-          return;
-        }
-        this._mm.removeMessageListener("debug:form", onFormUpdate);
-
-        resolve(msg.json);
-      };
-
-      this._mm.addMessageListener("debug:form", onFormUpdate);
-      this._mm.sendAsyncMessage("debug:form");
-    });
-
-    this._form = form;
-    if (this.options.favicons) {
-      this._form.favicon = await this.getFaviconData();
-    }
-
-    return this;
-  },
-
-  /**
-   * If we don't have a title from the content side because it's a zombie tab, try to find
-   * it on the chrome side.
-   */
-  get title() {
-    // On Fennec, we can check the session store data for zombie tabs
-    if (this._browser && this._browser.__SS_restore) {
-      const sessionStore = this._browser.__SS_data;
-      // Get the last selected entry
-      const entry = sessionStore.entries[sessionStore.index - 1];
-      return entry.title;
-    }
-    // If contentTitle is empty (e.g. on a not-yet-restored tab), but there is a
-    // tabbrowser (i.e. desktop Firefox, but not Fennec), we can use the label
-    // as the title.
-    if (this._tabbrowser) {
-      const tab = this._tabbrowser.getTabForBrowser(this._browser);
-      if (tab) {
-        return tab.label;
-      }
-    }
-    return "";
-  },
-
-  /**
-   * If we don't have a url from the content side because it's a zombie tab, try to find
-   * it on the chrome side.
-   */
-  get url() {
-    // On Fennec, we can check the session store data for zombie tabs
-    if (this._browser && this._browser.__SS_restore) {
-      const sessionStore = this._browser.__SS_data;
-      // Get the last selected entry
-      const entry = sessionStore.entries[sessionStore.index - 1];
-      return entry.url;
-    }
-    return null;
-  },
-
-  form() {
-    const form = Object.assign({}, this._form);
-    // In some cases, the title and url fields might be empty.  Zombie tabs (not yet
-    // restored) are a good example.  In such cases, try to look up values for these
-    // fields using other data in the parent process.
-    if (!form.title) {
-      form.title = this.title;
-    }
-    if (!form.url) {
-      form.url = this.url;
-    }
-
-    return form;
-  },
-
-  exit() {
-    this._browser = null;
-    this._form = null;
-    this.exited = true;
-  },
-};
-
-exports.BrowserTabActor = BrowserTabActor;
-
 function BrowserAddonList(connection) {
   this._connection = connection;
   this._actorByAddonId = new Map();
   this._onListChanged = null;
 }
 
 BrowserAddonList.prototype.getList = async function() {
   const addons = await AddonManager.getAllAddons();