drawWindow() broken with multiprocess Firefox (e10s)?

219 Views Asked by At

The Firefox drawWindow()-Function expects as first parameter a XUL content-window as provided by the low-level api tab utils.

However with the introduction of the multiprocess architecture in Firefox (codenamed electrolysis or e10s) directly accessing tabs via the low-level api is no longer possible. While there are compatibility shims available, it is explicitly stated that they do not support plattform APIs that expect DOM objects. On the other hand drawWindow() cannot be used in a content script since it is "chrome only".

So my questions are these:

  1. How am I supposed to use drawWindow() if I cannot use it outside of chrome and cannot get a contentWindow-object within chrome?
  2. What are my other options to let my addon take screenshots of websites within multiprocess Firefox?

Our current approach is based on the answer to this SO question. However it will not work with multiprocess Firefox

1

There are 1 best solutions below

1
On BEST ANSWER

The solution to using drawWindow() was indeed to use framescripts as Noitidart suggested in the comments. The framescript I use for the screenshots looks like this:

addMessageListener("fs/make_screenshot_from_rectangle", makeScreenshot);

function makeScreenshot(payload) {
    var rectangle = payload.data;
    var startX = rectangle.startX || 0;
    var startY = rectangle.startY || 0;
    var width = rectangle.width || content.innerWidth;
    var height = rectangle.height || content.innerHeight;
    // Create canvas to draw window unto
    var canvas = content.document.createElementNS("http://www.w3.org/1999/xhtml", "canvas");
    canvas.width = width;
    canvas.height = height;
    // Create context for drawing, draw the old window unto the canvas
    var context = canvas.getContext("2d");
    context.drawWindow(content, startX, startY, width, height, "rgb(255,255,255)");
    // Save context as png
    var image = canvas.toDataURL('image/png');
    sendAsyncMessage("got-screenshot", image);
}

And it is called from a chrome-script with the following function:

function (rectangle) {
    var tab = require("sdk/tabs").activeTab;
    var xulTab = require("sdk/view/core").viewFor(tab);
    var xulBrowser = require("sdk/tabs/utils").getBrowserForTab(xulTab);

    var browserMM = xulBrowser.messageManager;
    if ( /* framescript not yet attached to tab */ ) {
        browserMM.loadFrameScript(require("sdk/self").data.url("content-scripts/frame-script.js"), false);
        ... // do something to remember that there is a framescript attached to the tab
        browserMM.addMessageListener("got-screenshot", function (payload) {
            ... // handle the screenshot
        });
    }
    browserMM.sendAsyncMessage('fs/make_screenshot_from_rectangle', rectangle);
}

Relevant reading: