Bug 1573254: Part 1 - Support remote windows in SpecialPowers.snapshotWindow. r=mccr8
authorKris Maglione <maglione.k@gmail.com>
Mon, 12 Aug 2019 12:55:06 -0700
changeset 488076 c3db0f8fbc5b2ac742da75e8295052d5d9510306
parent 488075 1d8042fdc2b8a6ec78169a33d2648db97b2131c4
child 488077 4b826e607ca87939b656b62836721973c67dac71
push id36435
push usercbrindusan@mozilla.com
push dateThu, 15 Aug 2019 09:46:49 +0000
treeherdermozilla-central@0db07ff50ab5 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmccr8
bugs1573254
milestone70.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 1573254: Part 1 - Support remote windows in SpecialPowers.snapshotWindow. r=mccr8 Differential Revision: https://phabricator.services.mozilla.com/D41629
testing/specialpowers/content/SpecialPowersAPI.jsm
--- a/testing/specialpowers/content/SpecialPowersAPI.jsm
+++ b/testing/specialpowers/content/SpecialPowersAPI.jsm
@@ -1136,55 +1136,91 @@ class SpecialPowersAPI extends JSWindowA
 
   emulateMedium(window, mediaType) {
     this._getMUDV(window).emulateMedium(mediaType);
   }
   stopEmulatingMedium(window) {
     this._getMUDV(window).stopEmulatingMedium();
   }
 
-  snapshotWindowWithOptions(win, rect, bgcolor, options) {
-    var el = this.document.createElementNS(
-      "http://www.w3.org/1999/xhtml",
-      "canvas"
-    );
-    if (rect === undefined) {
-      rect = {
-        top: win.scrollY,
-        left: win.scrollX,
-        width: win.innerWidth,
-        height: win.innerHeight,
-      };
-    }
-    if (bgcolor === undefined) {
-      bgcolor = "rgb(255,255,255)";
-    }
-    if (options === undefined) {
-      options = {};
+  // Takes a snapshot of the given window and returns a <canvas>
+  // containing the image. When the window is same-process, the canvas
+  // is returned synchronously. When it is out-of-process (or when a
+  // BrowsingContext or FrameLoaderOwner is passed instead of a Window),
+  // a promise which resolves to such a canvas is returned instead.
+  snapshotWindowWithOptions(content, rect, bgcolor, options) {
+    function getImageData(rect, bgcolor, options) {
+      let el = content.document.createElementNS(
+        "http://www.w3.org/1999/xhtml",
+        "canvas"
+      );
+      if (rect === undefined) {
+        rect = {
+          top: content.scrollY,
+          left: content.scrollX,
+          width: content.innerWidth,
+          height: content.innerHeight,
+        };
+      }
+      if (bgcolor === undefined) {
+        bgcolor = "rgb(255,255,255)";
+      }
+      if (options === undefined) {
+        options = {};
+      }
+
+      el.width = rect.width;
+      el.height = rect.height;
+      let ctx = el.getContext("2d");
+
+      let flags = 0;
+      for (let option in options) {
+        flags |= options[option] && ctx[option];
+      }
+
+      ctx.drawWindow(
+        content,
+        rect.left,
+        rect.top,
+        rect.width,
+        rect.height,
+        bgcolor,
+        flags
+      );
+
+      return ctx.getImageData(0, 0, el.width, el.height);
     }
 
-    el.width = rect.width;
-    el.height = rect.height;
-    var ctx = el.getContext("2d");
-    var flags = 0;
+    let toCanvas = imageData => {
+      let el = this.document.createElementNS(
+        "http://www.w3.org/1999/xhtml",
+        "canvas"
+      );
+      el.width = imageData.width;
+      el.height = imageData.height;
 
-    for (var option in options) {
-      flags |= options[option] && ctx[option];
+      let ctx = el.getContext("2d");
+      ctx.putImageData(imageData, 0, 0);
+
+      return el;
+    };
+
+    if (Window.isInstance(content)) {
+      // This is an in-process window. Snapshot it synchronously.
+      return toCanvas(getImageData(rect, bgcolor, options));
     }
 
-    ctx.drawWindow(
-      win,
-      rect.left,
-      rect.top,
-      rect.width,
-      rect.height,
-      bgcolor,
-      flags
+    // This is a remote window or frame. Snapshot it asynchronously and
+    // return a promise for the result. Alas, consumers expect us to
+    // return a <canvas> element rather than an ImageData object, so we
+    // need to convert the result from the remote snapshot to a local
+    // canvas.
+    return this.spawn(content, [rect, bgcolor, options], getImageData).then(
+      toCanvas
     );
-    return el;
   }
 
   snapshotWindow(win, withCaret, rect, bgcolor) {
     return this.snapshotWindowWithOptions(win, rect, bgcolor, {
       DRAWWINDOW_DRAW_CARET: withCaret,
     });
   }