Bug 1579133 - Screenshot page content with embedded RDM UI. r=gl
authorMicah Tigley <mtigley@mozilla.com>
Mon, 30 Sep 2019 14:59:01 +0000
changeset 495697 ab8923caa59404dd5b2a67204281584ee6d858b2
parent 495696 a3afb69b01cf0a296927d39c8b04146bdc9fa8b7
child 495698 59693d9d9f6036e10fe4656e9c86f52749e8e827
push id114140
push userdvarga@mozilla.com
push dateWed, 02 Oct 2019 18:04:51 +0000
treeherdermozilla-inbound@32eb0ea893f3 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersgl
bugs1579133
milestone71.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 1579133 - Screenshot page content with embedded RDM UI. r=gl Adds another method on the Emulation actor that screenshots the page content. Here, another instance of the ScreenshotActor is managed by the Emulation actor. The ScreenshotActor already provides methods to handle capturing page content along with additional options such as screenshotting the full page, which we may want to use in the future. Differential Revision: https://phabricator.services.mozilla.com/D46092
devtools/client/responsive/actions/screenshot.js
devtools/client/responsive/ui.js
devtools/server/actors/emulation.js
devtools/shared/specs/emulation.js
--- a/devtools/client/responsive/actions/screenshot.js
+++ b/devtools/client/responsive/actions/screenshot.js
@@ -11,16 +11,18 @@ const Services = require("Services");
 const { TAKE_SCREENSHOT_START, TAKE_SCREENSHOT_END } = require("./index");
 
 const { getFormatStr } = require("../utils/l10n");
 const { getTopLevelWindow } = require("../utils/window");
 const e10s = require("../utils/e10s");
 
 const CAMERA_AUDIO_URL = "resource://devtools/client/themes/audio/shutter.wav";
 
+const message = require("../utils/message");
+
 const animationFrame = () =>
   new Promise(resolve => {
     window.requestAnimationFrame(resolve);
   });
 
 function getFileName() {
   const date = new Date();
   const month = ("0" + (date.getMonth() + 1)).substr(-2);
@@ -60,26 +62,33 @@ function simulateCameraEffects(node) {
     const cameraAudio = new window.Audio(CAMERA_AUDIO_URL);
     cameraAudio.play();
   }
   node.animate({ opacity: [0, 1] }, 500);
 }
 
 module.exports = {
   takeScreenshot() {
-    return async function(dispatch, getState) {
+    return async function(dispatch) {
       await dispatch({ type: TAKE_SCREENSHOT_START });
 
       // Waiting the next repaint, to ensure the react components
       // can be properly render after the action dispatched above
       await animationFrame();
 
-      const iframe = document.querySelector("iframe");
-      const data = await createScreenshotFor(iframe);
+      if (
+        !Services.prefs.getBoolPref("devtools.responsive.browserUI.enabled")
+      ) {
+        const iframe = document.querySelector("iframe");
+        const data = await createScreenshotFor(iframe);
 
-      simulateCameraEffects(iframe);
+        simulateCameraEffects(iframe);
 
-      saveToFile(data, getFileName());
+        saveToFile(data, getFileName());
+      } else {
+        window.postMessage({ type: "screenshot" }, "*");
+        await message.wait(window, "screenshot-captured");
+      }
 
       dispatch({ type: TAKE_SCREENSHOT_END });
     };
   },
 };
--- a/devtools/client/responsive/ui.js
+++ b/devtools/client/responsive/ui.js
@@ -40,16 +40,21 @@ loader.lazyRequireGetter(
 loader.lazyRequireGetter(
   this,
   "showNotification",
   "devtools/client/responsive/utils/notification",
   true
 );
 loader.lazyRequireGetter(this, "l10n", "devtools/client/responsive/utils/l10n");
 loader.lazyRequireGetter(this, "asyncStorage", "devtools/shared/async-storage");
+loader.lazyRequireGetter(
+  this,
+  "saveScreenshot",
+  "devtools/shared/screenshot/save"
+);
 
 const TOOL_URL = "chrome://devtools/content/responsive/index.xhtml";
 
 const RELOAD_CONDITION_PREF_PREFIX = "devtools.responsive.reloadConditions.";
 const RELOAD_NOTIFICATION_PREF =
   "devtools.responsive.reloadNotification.enabled";
 
 function debug(msg) {
@@ -426,16 +431,18 @@ class ResponsiveUI {
         this.onRemoveDeviceAssociation();
         break;
       case "viewport-orientation-change":
         this.onRotateViewport(event);
         break;
       case "viewport-resize":
         this.onResizeViewport(event);
         break;
+      case "screenshot":
+        this.onScreenshot();
     }
   }
 
   async onChangeDevice(event) {
     const { pixelRatio, touch, userAgent } = event.data.device;
     let reloadNeeded = false;
     await this.updateDPPX(pixelRatio);
 
@@ -528,16 +535,31 @@ class ResponsiveUI {
     });
   }
 
   async onRotateViewport(event) {
     const { orientationType: type, angle, isViewportRotated } = event.data;
     await this.updateScreenOrientation(type, angle, isViewportRotated);
   }
 
+  async onScreenshot() {
+    const targetFront = await this.client.mainRoot.getTab();
+    const captureScreenshotSupported = await targetFront.actorHasMethod(
+      "emulation",
+      "captureScreenshot"
+    );
+
+    if (captureScreenshotSupported) {
+      const data = await this.emulationFront.captureScreenshot();
+      await saveScreenshot(this.browserWindow, {}, data);
+
+      message.post(this.rdmFrame.contentWindow, "screenshot-captured");
+    }
+  }
+
   /**
    * Restores the previous state of RDM.
    */
   async restoreState() {
     const deviceState = await asyncStorage.getItem(
       "devtools.responsive.deviceState"
     );
     if (deviceState) {
--- a/devtools/server/actors/emulation.js
+++ b/devtools/server/actors/emulation.js
@@ -5,16 +5,22 @@
 "use strict";
 
 const { Ci } = require("chrome");
 const protocol = require("devtools/shared/protocol");
 const { emulationSpec } = require("devtools/shared/specs/emulation");
 
 loader.lazyRequireGetter(
   this,
+  "ScreenshotActor",
+  "devtools/server/actors/screenshot",
+  true
+);
+loader.lazyRequireGetter(
+  this,
   "TouchSimulator",
   "devtools/server/actors/emulation/touch-simulator",
   true
 );
 
 /**
  * This actor overrides various browser features to simulate different environments to
  * test how pages perform under various conditions.
@@ -49,16 +55,17 @@ const EmulationActor = protocol.ActorCla
     this.clearMetaViewportOverride();
     this.clearUserAgentOverride();
 
     this.targetActor.off("will-navigate", this.onWillNavigate);
     this.targetActor.off("window-ready", this.onWindowReady);
 
     this.targetActor = null;
     this.docShell = null;
+    this._screenshotActor = null;
     this._touchSimulator = null;
 
     protocol.Actor.prototype.destroy.call(this);
   },
 
   /**
    * Retrieve the console actor for this tab.  This allows us to expose network throttling
    * as part of emulation settings, even though it's internally connected to the network
@@ -67,16 +74,25 @@ const EmulationActor = protocol.ActorCla
   get _consoleActor() {
     if (this.targetActor.exited || !this.targetActor.actorID) {
       return null;
     }
     const form = this.targetActor.form();
     return this.conn._getOrCreateActor(form.consoleActor);
   },
 
+  get screenshotActor() {
+    if (!this._screenshotActor) {
+      this._screenshotActor = new ScreenshotActor(this.conn, this.targetActor);
+      this.manage(this._screenshotActor);
+    }
+
+    return this._screenshotActor;
+  },
+
   get touchSimulator() {
     if (!this._touchSimulator) {
       this._touchSimulator = new TouchSimulator(
         this.targetActor.chromeEventHandler
       );
     }
 
     return this._touchSimulator;
@@ -389,11 +405,15 @@ const EmulationActor = protocol.ActorCla
     }
 
     const { CustomEvent } = this.win;
     const orientationChangeEvent = new CustomEvent("orientationchange");
 
     this.setScreenOrientation(type, angle);
     this.win.dispatchEvent(orientationChangeEvent);
   },
+
+  async captureScreenshot() {
+    return this.screenshotActor.capture({});
+  },
 });
 
 exports.EmulationActor = EmulationActor;
--- a/devtools/shared/specs/emulation.js
+++ b/devtools/shared/specs/emulation.js
@@ -153,12 +153,19 @@ const emulationSpec = generateActorSpec(
     simulateScreenOrientationChange: {
       request: {
         orientation: Arg(0, "string"),
         angle: Arg(1, "number"),
         deviceChange: Arg(2, "boolean"),
       },
       response: {},
     },
+
+    captureScreenshot: {
+      request: {},
+      response: {
+        value: RetVal("json"),
+      },
+    },
   },
 });
 
 exports.emulationSpec = emulationSpec;