Bug 1474006 - Work in progress draft
authorAlexandre Poirot <poirot.alex@gmail.com>
Fri, 20 Jul 2018 01:57:47 -0700
changeset 820735 5e2325f1ae8b97ee57b80de9b54c82223cbfc5f6
parent 820343 183ee39bf309cd8463d8db5b5c8eb232cd0dac53
push id116911
push userbmo:poirot.alex@gmail.com
push dateFri, 20 Jul 2018 09:03:16 +0000
bugs1474006
milestone63.0a1
Bug 1474006 - Work in progress This code shows a way to retrieve the content of the tab from the parent process by using the message manager. It requires additional work to merge this screenshot into the parent process one by using Canvas API, as well as polish and a test. It mostly highlights how to do the cross process communication via message managers in order to retrieve the missing piece of the screenshot. I'm not planning to finish this patch, so anyone is free to pick this up. MozReview-Commit-ID: 3Vm9xbr0Y0R
devtools/server/actors/webconsole/screenshot.js
--- a/devtools/server/actors/webconsole/screenshot.js
+++ b/devtools/server/actors/webconsole/screenshot.js
@@ -44,16 +44,49 @@ function captureScreenshot(args, documen
   return createScreenshotData(document, args);
 }
 
 /**
  * This does the dirty work of creating a base64 string out of an
  * area of the browser window
  */
 function createScreenshotData(document, args) {
+  if (document.location.href.includes("browser.xul")) { // if we are in browser console codepath
+    // Get the message manager for the current tab
+    // document should be a reference to the topmost firefox window (I think)
+    // otherwise `Services.wm.getMostRecentWindow("navigator:browser")`  returns it for sure
+    const { messageManager } = document.defaultView.gBrowser.selectedBrowser;
+    // you may already be used to such data + stringified function trick, we use that in ContentTask
+    // an important thing to know is that stringification doesn't like comments because it stringify without "\n"
+    // It is very hard to have comments in them, /* */ are supposed to work but I wasn't able to have them working here...
+    /* In a "frame script", you have access to some special globals like `content` */
+    /*   which is the window object of the current content document */
+    /*   More globals listed here: https://searchfox.org/mozilla-central/source/dom/chrome-webidl/MessageManager.webidl#464-492 */
+    messageManager.loadFrameScript("data:,new " + function () {
+      const { require } = ChromeUtils.import("resource://devtools/shared/Loader.jsm", {});
+      const { createScreenshotData } = require("devtools/server/actors/webconsole/screenshot");
+      const onMessage = async (msg) => {
+        removeMessageListener("debug:screenshot-command", onMessage);
+
+        const data = await createScreenshotData(content.document, msg.data);
+        sendAsyncMessage("debug:screenshot-command", data);
+      };
+      addMessageListener("debug:screenshot-command", onMessage);
+    }, false /* false as we want to execute it only against the current document and not the next one to come */);
+             /* https://searchfox.org/mozilla-central/source/dom/chrome-webidl/MessageManager.webidl#391-400 */
+
+    return new Promise(resolve => {
+      const onMessage = (msg) => {
+        messageManager.removeMessageListener("debug:screenshot-command", onMessage);
+        resolve(msg.data);
+      };
+      messageManager.addMessageListener("debug:screenshot-command", onMessage);
+      messageManager.sendAsyncMessage("debug:screenshot-command", args);
+    });
+  }
   const window = document.defaultView;
   let left = 0;
   let top = 0;
   let width;
   let height;
   const currentX = window.scrollX;
   const currentY = window.scrollY;
 
@@ -106,16 +139,17 @@ function createScreenshotData(document, 
   return Promise.resolve({
     destinations: [],
     data: data,
     height: height,
     width: width,
     filename: filename,
   });
 }
+exports.createScreenshotData = createScreenshotData;
 
 /**
  * We may have a filename specified in args, or we might have to generate
  * one.
  */
 function getFilename(defaultName) {
   // Create a name for the file if not present
   if (defaultName) {