diff options
Diffstat (limited to 'devtools/server/actors/screenshot-content.js')
-rw-r--r-- | devtools/server/actors/screenshot-content.js | 144 |
1 files changed, 144 insertions, 0 deletions
diff --git a/devtools/server/actors/screenshot-content.js b/devtools/server/actors/screenshot-content.js new file mode 100644 index 0000000000..0e47ae1157 --- /dev/null +++ b/devtools/server/actors/screenshot-content.js @@ -0,0 +1,144 @@ +/* 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<Object{text, level}>}: 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, + }; + } +}; |