Bug 1336308: Part 2 - Add a TabBase.sendMessage and TabBase.capture helper methods. r?aswan draft
authorKris Maglione <maglione.k@gmail.com>
Fri, 03 Feb 2017 13:00:39 -0800
changeset 470554 b6674a9c45b36773cbf80bdb55e5d22aaab2b843
parent 470026 581e8a912977ccfce779de8462bcd2497eb45d4a
child 470555 a334e32060e469fdfdd2fc42c88c0e45739e4956
push id44075
push usermaglione.k@gmail.com
push dateFri, 03 Feb 2017 23:30:42 +0000
reviewersaswan
bugs1336308
milestone54.0a1
Bug 1336308: Part 2 - Add a TabBase.sendMessage and TabBase.capture helper methods. r?aswan MozReview-Commit-ID: EP8uxCkztvi
browser/components/extensions/ext-tabs.js
mobile/android/components/extensions/ext-tabs.js
toolkit/components/extensions/ExtensionTabs.jsm
--- a/browser/components/extensions/ext-tabs.js
+++ b/browser/components/extensions/ext-tabs.js
@@ -517,63 +517,31 @@ extensions.registerSchemaAPI("tabs", "ad
           queryInfo = Object.assign({}, queryInfo);
           queryInfo.url = new MatchPattern(queryInfo.url);
         }
 
         return Array.from(tabManager.query(queryInfo, context),
                           tab => tab.convert());
       },
 
-      captureVisibleTab(windowId, options) {
-        if (!extension.hasPermission("<all_urls>")) {
-          return Promise.reject({message: "The <all_urls> permission is required to use the captureVisibleTab API"});
-        }
-
+      async captureVisibleTab(windowId, options) {
         let window = windowId == null ?
           windowTracker.topWindow :
           windowTracker.getWindow(windowId, context);
 
-        let tab = window.gBrowser.selectedTab;
-        return tabListener.awaitTabReady(tab).then(() => {
-          let browser = tab.linkedBrowser;
-          let recipient = {
-            innerWindowID: browser.innerWindowID,
-          };
+        let tab = tabManager.wrapTab(window.gBrowser.selectedTab);
+        await tabListener.awaitTabReady(tab.tab);
 
-          if (!options) {
-            options = {};
-          }
-          if (options.format == null) {
-            options.format = "png";
-          }
-          if (options.quality == null) {
-            options.quality = 92;
-          }
-
-          let message = {
-            options,
-            width: browser.clientWidth,
-            height: browser.clientHeight,
-          };
-
-          return context.sendMessage(browser.messageManager, "Extension:Capture",
-                                     message, {recipient});
-        });
+        return tab.capture(context, options);
       },
 
       async detectLanguage(tabId) {
-        let tab = getTabOrActive(tabId);
+        let tab = await promiseTabWhenReady(tabId);
 
-        return tabListener.awaitTabReady(tab).then(() => {
-          let browser = tab.linkedBrowser;
-          let recipient = {innerWindowID: browser.innerWindowID};
-
-          return context.sendMessage(browser.messageManager, "Extension:DetectLanguage",
-                                     {}, {recipient});
-        });
+        return tab.sendMessage(context, "Extension:DetectLanguage");
       },
 
       async executeScript(tabId, details) {
         let tab = await promiseTabWhenReady(tabId);
 
         return tab.executeScript(context, details);
       },
 
--- a/mobile/android/components/extensions/ext-tabs.js
+++ b/mobile/android/components/extensions/ext-tabs.js
@@ -395,51 +395,25 @@ extensions.registerSchemaAPI("tabs", "ad
           queryInfo = Object.assign({}, queryInfo);
           queryInfo.url = new MatchPattern(queryInfo.url);
         }
 
         return Array.from(tabManager.query(queryInfo, context),
                           tab => tab.convert());
       },
 
-      captureVisibleTab(windowId, options) {
-        if (!extension.hasPermission("<all_urls>")) {
-          return Promise.reject({message: "The <all_urls> permission is required to use the captureVisibleTab API"});
-        }
-
+      async captureVisibleTab(windowId, options) {
         let window = windowId == null ?
           windowTracker.topWindow :
           windowTracker.getWindow(windowId, context);
 
-        let tab = window.BrowserApp.selectedTab;
-        return tabListener.awaitTabReady(tab).then(() => {
-          let {browser} = tab;
-          let recipient = {
-            innerWindowID: browser.innerWindowID,
-          };
+        let tab = tabManager.wrapTab(window.BrowserApp.selectedTab);
+        await tabListener.awaitTabReady(tab.tab);
 
-          if (!options) {
-            options = {};
-          }
-          if (options.format == null) {
-            options.format = "png";
-          }
-          if (options.quality == null) {
-            options.quality = 92;
-          }
-
-          let message = {
-            options,
-            width: browser.clientWidth,
-            height: browser.clientHeight,
-          };
-
-          return context.sendMessage(browser.messageManager, "Extension:Capture",
-                                     message, {recipient});
-        });
+        return tab.capture(context, options);
       },
 
       async executeScript(tabId, details) {
         let tab = await promiseTabWhenReady(tabId);
 
         return tab.executeScript(context, details);
       },
 
--- a/toolkit/components/extensions/ExtensionTabs.jsm
+++ b/toolkit/components/extensions/ExtensionTabs.jsm
@@ -31,16 +31,80 @@ class TabBase {
   constructor(extension, tab, id) {
     this.extension = extension;
     this.tabManager = extension.tabManager;
     this.id = id;
     this.tab = tab;
     this.activeTabWindowID = null;
   }
 
+  /**
+   * Sends a message, via the given context, to the ExtensionContent running in
+   * this tab. The tab's current innerWindowID is automatically added to the
+   * recipient filter for the message, and is used to ensure that the message is
+   * not processed if the content process navigates to a different content page
+   * before the message is received.
+   *
+   * @param {BaseContext} context
+   *        The context through which to send the message.
+   * @param {string} messageName
+   *        The name of the messge to send.
+   * @param {object} [data = {}]
+   *        Arbitrary, structured-clonable message data to send.
+   * @param {object} [options]
+   *        An options object, as accepted by BaseContext.sendMessage.
+   *
+   * @returns {Promise}
+   */
+  sendMessage(context, messageName, data = {}, options = null) {
+    let {browser, innerWindowID} = this;
+
+    options = Object.assign({}, options);
+    options.recipient = Object.assign({innerWindowID}, options.recipient);
+
+    return context.sendMessage(browser.messageManager, messageName,
+                               data, options);
+  }
+
+  /**
+   * Capture the visible area of this tab, and return the result as a data: URL.
+   *
+   * @param {BaseContext} context
+   *        The extension context for which to perform the capture.
+   * @param {Object} [options]
+   *        The options with which to perform the capture.
+   * @param {string} [options.format = "png"]
+   *        The image format in which to encode the captured data. May be one of
+   *        "png" or "jpeg".
+   * @param {integer} [options.quality = 92]
+   *        The quality at which to encode the captured image data, ranging from
+   *        0 to 100. Has no effect for the "png" format.
+   *
+   * @returns {Promise<string>}
+   */
+  capture(context, options = null) {
+    if (!options) {
+      options = {};
+    }
+    if (options.format == null) {
+      options.format = "png";
+    }
+    if (options.quality == null) {
+      options.quality = 92;
+    }
+
+    let message = {
+      options,
+      width: this.width,
+      height: this.height,
+    };
+
+    return this.sendMessage(context, "Extension:Capture", message);
+  }
+
   get innerWindowID() {
     return this.browser.innerWindowID;
   }
 
   get hasTabPermission() {
     return this.extension.hasPermission("tabs") || this.hasActiveTabPermission;
   }
 
@@ -191,22 +255,17 @@ class TabBase {
       options.run_at = "document_idle";
     }
     if (details.cssOrigin !== null) {
       options.css_origin = details.cssOrigin;
     } else {
       options.css_origin = "author";
     }
 
-    let {browser} = this;
-    let recipient = {
-      innerWindowID: browser.innerWindowID,
-    };
-
-    return context.sendMessage(browser.messageManager, "Extension:Execute", {options}, {recipient});
+    return this.sendMessage(context, "Extension:Execute", {options});
   }
 
   executeScript(context, details) {
     return this._execute(context, details, "js", "executeScript");
   }
 
   insertCSS(context, details) {
     return this._execute(context, details, "css", "insertCSS").then(() => {});