/* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ "use strict"; const { Actor } = require("resource://devtools/shared/protocol.js"); const { screenshotContentSpec, } = require("resource://devtools/shared/specs/screenshot-content.js"); const { LocalizationHelper } = require("resource://devtools/shared/l10n.js"); const STRINGS_URI = "devtools/shared/locales/screenshot.properties"; const L10N = new LocalizationHelper(STRINGS_URI); loader.lazyRequireGetter( this, ["getCurrentZoom", "getRect"], "resource://devtools/shared/layout/utils.js", true ); exports.ScreenshotContentActor = class ScreenshotContentActor extends Actor { constructor(conn, targetActor) { super(conn, screenshotContentSpec); this.targetActor = targetActor; } _getRectForNode(node) { const originWindow = this.targetActor.ignoreSubFrames ? node.ownerGlobal : node.ownerGlobal.top; return getRect(originWindow, node, node.ownerGlobal); } /** * Retrieve some window-related information that will be passed to the parent process * to actually generate the screenshot. * * @param {Object} args * @param {Boolean} args.fullpage: Should the screenshot be the height of the whole page * @param {String} args.selector: A CSS selector for the element we should take the * screenshot of. The function will return true for the `error` property * if the screenshot does not match any element. * @param {String} args.nodeActorID: The actorID of the node actor matching the element * we should take the screenshot of. * @returns {Object} An object with the following properties: * - error {Boolean}: Set to true if an issue was encountered that prevents * taking the screenshot * - messages {Array}: An array of objects representing * the messages emitted throught the process and their level. * - windowDpr {Number}: Value of window.devicePixelRatio * - windowZoom {Number}: The page current zoom level * - rect {Object}: Object with left, top, width and height properties * representing the rect **inside the browser element** that should be rendered. * For screenshot of the current viewport, we return null, as expected by the * `drawSnapshot` API. */ prepareCapture({ fullpage, selector, nodeActorID }) { const { window } = this.targetActor; // Use the override if set, note that the override is not returned by // devicePixelRatio on privileged code, see bug 1759962. // // FIXME(bug 1760711): Whether zoom is included in devicePixelRatio depends // on whether there's an override, this is a bit suspect. const windowDpr = window.browsingContext.top.overrideDPPX || window.devicePixelRatio; const windowZoom = getCurrentZoom(window); const messages = []; // If we're going to take the current view of the page, we don't need to compute a rect, // since it's the default behaviour of drawSnapshot. if (!fullpage && !selector && !nodeActorID) { return { rect: null, messages, windowDpr, windowZoom, }; } let left; let top; let width; let height; if (fullpage) { // We don't want to render the scrollbars const winUtils = window.windowUtils; const scrollbarHeight = {}; const scrollbarWidth = {}; winUtils.getScrollbarSize(false, scrollbarWidth, scrollbarHeight); left = 0; top = 0; width = window.innerWidth + window.scrollMaxX - window.scrollMinX - scrollbarWidth.value; height = window.innerHeight + window.scrollMaxY - window.scrollMinY - scrollbarHeight.value; } else if (selector) { const node = window.document.querySelector(selector); if (!node) { messages.push({ level: "warn", text: L10N.getFormatStr("screenshotNoSelectorMatchWarning", selector), }); return { error: true, messages, }; } ({ left, top, width, height } = this._getRectForNode(node)); } else if (nodeActorID) { const nodeActor = this.conn.getActor(nodeActorID); if (!nodeActor) { messages.push({ level: "error", text: `Screenshot actor failed to find Node actor for '${nodeActorID}'`, }); return { error: true, messages, }; } ({ left, top, width, height } = this._getRectForNode(nodeActor.rawNode)); } return { windowDpr, windowZoom, rect: { left, top, width, height }, messages, }; } };