gecko-dev/testing/marionette/capture.js
Andreas Tolfsen 30ee512caa Bug 1213797: Refactor screen capture and SVG document support
Errors thrown by takeScreenshot used to be silently ignored.  When the
command started using the new dispatching technique in bug 1202663,
it was surfaced we do not support taking screen captures of SVG documents.

Since this is a requirement for Web Platform Tests, this patch corrects
the wrong assumptions about document body and document element.

This patch also significantly refactors the screen capture code, but
only uses the new implementation in contnent space, since some further
modifications are required to use it in chrome.

r=dburns
r=jgriffin

--HG--
extra : commitid : DdCIEpd5PEJ
extra : rebase_source : 7357010f992d7f995765c685000892cc59d9ec9a
2015-10-13 16:52:26 +01:00

143 lines
3.8 KiB
JavaScript

/* 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";
this.EXPORTED_SYMBOLS = ["capture"];
const CONTEXT_2D = "2d";
const BG_COLOUR = "rgb(255,255,255)";
const PNG_MIME = "image/png";
const XHTML_NS = "http://www.w3.org/1999/xhtml";
/** Provides primitives to capture screenshots. */
this.capture = {};
/**
* Take a screenshot of a single element.
*
* @param {Node} node
* The node to take a screenshot of.
* @param {Array.<Node>=} highlights
* Optional array of nodes, around which a border will be marked to
* highlight them in the screenshot.
*
* @return {HTMLCanvasElement}
* The canvas element where the element has been painted on.
*/
capture.element = function(node, highlights=[]) {
let doc = node.ownerDocument;
let win = doc.defaultView;
let rect = node.getBoundingClientRect();
return capture.canvas(
doc,
rect.left,
rect.top,
rect.width,
rect.height,
highlights);
};
/**
* Take a screenshot of the document's viewport, taking into account
* the current window's offset.
*
* @param {Document} document
* The DOM document providing the document element to capture,
* and a window for determining the offset of the viewport.
* @param {Array.<Node>=} highlights
* Optional array of nodes, around which a border will be marked to
* highlight them in the screenshot.
*
* @return {HTMLCanvasElement}
* The canvas element where the viewport has been painted on.
*/
capture.viewport = function(document, highlights=[]) {
let win = document.defaultView;
let docEl = document.documentElement;
return capture.canvas(
document,
win.pageXOffset,
win.pageYOffset,
docEl.clientWidth,
docEl.clientHeight,
highlights);
};
/**
* Low-level interface to draw a rectangle off the framebuffer.
*
* @param {Document} document
* A DOM document providing the window used to the framebuffer,
* and interfaces for creating an HTMLCanvasElement.
* @param {number} left
* The left, X axis offset of the rectangle.
* @param {number} top
* The top, Y axis offset of the rectangle.
* @param {number} width
* The width dimension of the rectangle to paint.
* @param {number} height
* The height dimension of the rectangle to paint.
* @param {Array.<Node>=} highlights
* Optional array of nodes, around which a border will be marked to
* highlight them in the screenshot.
*
* @return {HTMLCanvasElement}
* The canvas on which the selection from the window's framebuffer
* has been painted on.
*/
capture.canvas = function(document, left, top, width, height, highlights=[]) {
let win = document.defaultView;
let canvas = document.createElementNS(XHTML_NS, "canvas");
canvas.width = width;
canvas.height = height;
let ctx = canvas.getContext(CONTEXT_2D);
ctx.drawWindow(win, left, top, width, height, BG_COLOUR);
ctx = capture.highlight_(ctx, highlights, top, left);
return canvas;
};
capture.highlight_ = function(context, highlights, top=0, left=0) {
if (!highlights) {
return;
}
context.lineWidth = "2";
context.strokeStyle = "red";
context.save();
for (let el of highlights) {
let rect = el.getBoundingClientRect();
let oy = -top;
let ox = -left;
context.strokeRect(
rect.left + ox,
rect.top + oy,
rect.width,
rect.height);
}
return context;
};
/**
* Encode the contents of an HTMLCanvasElement to a Base64 encoded string.
*
* @param {HTMLCanvasElement} canvas
* The canvas to encode.
*
* @return {string}
* A Base64 encoded string.
*/
capture.toBase64 = function(canvas) {
let u = canvas.toDataURL(PNG_MIME);
return u.substring(u.indexOf(",") + 1);
};