зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1559592 - [marionette] Take screenshots for content in parent process. r=webdriver-reviewers,ato,automatedtester
This moves all the screenshot related code from the framescript to the parent process, so that canvas.js is no longer called from within a content process. The remaining code in the framescript is only needed to compute the dimensions of the screenshot, and from all the to highlight elements. This move is necessary to allow switching to the new drawSnapshot API which only works from within the parent process. Differential Revision: https://phabricator.services.mozilla.com/D40209 --HG-- extra : moz-landing-system : lando
This commit is contained in:
Родитель
438d627e3d
Коммит
a4b63bd323
|
@ -37,44 +37,7 @@ capture.Format = {
|
|||
};
|
||||
|
||||
/**
|
||||
* Take a screenshot of a single element.
|
||||
*
|
||||
* @param {Node} node
|
||||
* The node to take a screenshot of.
|
||||
*
|
||||
* @return {HTMLCanvasElement}
|
||||
* The canvas element where the element has been painted on.
|
||||
*/
|
||||
capture.element = function(node) {
|
||||
let win = node.ownerGlobal;
|
||||
let rect = node.getBoundingClientRect();
|
||||
|
||||
return capture.canvas(win, rect.left, rect.top, rect.width, rect.height);
|
||||
};
|
||||
|
||||
/**
|
||||
* Take a screenshot of the window's viewport by taking into account
|
||||
* the current offsets.
|
||||
*
|
||||
* @param {DOMWindow} win
|
||||
* The DOM window providing the document element to capture,
|
||||
* and the offsets for the viewport.
|
||||
*
|
||||
* @return {HTMLCanvasElement}
|
||||
* The canvas element where the viewport has been painted on.
|
||||
*/
|
||||
capture.viewport = function(win) {
|
||||
return capture.canvas(
|
||||
win,
|
||||
win.pageXOffset,
|
||||
win.pageYOffset,
|
||||
win.innerWidth,
|
||||
win.innerHeight
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* Low-level interface to draw a rectangle off the framebuffer.
|
||||
* Draw a rectangle off the framebuffer.
|
||||
*
|
||||
* @param {DOMWindow} win
|
||||
* The DOM window used for the framebuffer, and providing the interfaces
|
||||
|
@ -92,6 +55,10 @@ capture.viewport = function(win) {
|
|||
* @param {number=} flags
|
||||
* Optional integer representing flags to pass to drawWindow; these
|
||||
* are defined on CanvasRenderingContext2D.
|
||||
* @param {number} dX
|
||||
* Horizontal offset between the browser window and content area. Defaults to 0.
|
||||
* @param {number} dY
|
||||
*. Vertical offset between the browser window and content area. Defaults to 0.
|
||||
*
|
||||
* @return {HTMLCanvasElement}
|
||||
* The canvas on which the selection from the window's framebuffer
|
||||
|
@ -103,7 +70,7 @@ capture.canvas = function(
|
|||
top,
|
||||
width,
|
||||
height,
|
||||
{ canvas = null, flags = null } = {}
|
||||
{ canvas = null, flags = null, dX = 0, dY = 0 } = {}
|
||||
) {
|
||||
const scale = win.devicePixelRatio;
|
||||
|
||||
|
@ -146,7 +113,7 @@ capture.canvas = function(
|
|||
}
|
||||
|
||||
ctx.scale(scale, scale);
|
||||
ctx.drawWindow(win, left, top, width, height, BG_COLOUR, flags);
|
||||
ctx.drawWindow(win, left + dX, top + dY, width, height, BG_COLOUR, flags);
|
||||
|
||||
return canvas;
|
||||
};
|
||||
|
|
|
@ -3019,7 +3019,7 @@ GeckoDriver.prototype.deleteSession = function() {
|
|||
* string. If <var>hash</var> is true, hex digest of the SHA-256
|
||||
* hash of the Base64 encoded string.
|
||||
*/
|
||||
GeckoDriver.prototype.takeScreenshot = function(cmd) {
|
||||
GeckoDriver.prototype.takeScreenshot = async function(cmd) {
|
||||
let win = assert.open(this.getCurrentWindow());
|
||||
|
||||
let { id, full, hash, scroll } = cmd.parameters;
|
||||
|
@ -3031,42 +3031,45 @@ GeckoDriver.prototype.takeScreenshot = function(cmd) {
|
|||
// Only consider full screenshot if no element has been specified
|
||||
full = id ? false : full;
|
||||
|
||||
let rect;
|
||||
let dY = 0;
|
||||
|
||||
switch (this.context) {
|
||||
case Context.Chrome:
|
||||
let canvas;
|
||||
|
||||
// element or full document element
|
||||
if (id || full) {
|
||||
let node;
|
||||
if (id) {
|
||||
let webEl = WebElement.fromUUID(id, Context.Chrome);
|
||||
node = this.curBrowser.seenEls.get(webEl);
|
||||
} else {
|
||||
node = win.document.documentElement;
|
||||
}
|
||||
|
||||
canvas = capture.element(node);
|
||||
|
||||
// viewport
|
||||
if (id) {
|
||||
let webEl = WebElement.fromUUID(id, this.context);
|
||||
let el = this.curBrowser.seenEls.get(webEl, win);
|
||||
rect = el.getBoundingClientRect();
|
||||
} else if (full) {
|
||||
rect = win.document.documentElement.getBoundingClientRect();
|
||||
} else {
|
||||
canvas = capture.viewport(win);
|
||||
}
|
||||
|
||||
switch (format) {
|
||||
case capture.Format.Hash:
|
||||
return capture.toHash(canvas);
|
||||
|
||||
case capture.Format.Base64:
|
||||
return capture.toBase64(canvas);
|
||||
// viewport
|
||||
rect = new win.DOMRect(
|
||||
win.pageXOffset,
|
||||
win.pageYOffset,
|
||||
win.innerWidth,
|
||||
win.innerHeight
|
||||
);
|
||||
}
|
||||
break;
|
||||
|
||||
case Context.Content:
|
||||
return this.listener.takeScreenshot(format, {
|
||||
id,
|
||||
full,
|
||||
scroll,
|
||||
});
|
||||
rect = await this.listener.getScreenshotRect({ id, full, scroll });
|
||||
// Temporarily needed until drawSnapshot() is used
|
||||
dY = win.gNavToolbox.clientHeight;
|
||||
break;
|
||||
}
|
||||
|
||||
let canvas = capture.canvas(win, rect.x, rect.y, rect.width, rect.height, {
|
||||
dY,
|
||||
});
|
||||
|
||||
switch (format) {
|
||||
case capture.Format.Hash:
|
||||
return capture.toHash(canvas);
|
||||
|
||||
case capture.Format.Base64:
|
||||
return capture.toBase64(canvas);
|
||||
}
|
||||
|
||||
throw new TypeError(`Unknown context: ${this.context}`);
|
||||
|
|
|
@ -23,9 +23,6 @@ const { atom } = ChromeUtils.import("chrome://marionette/content/atom.js");
|
|||
const { Capabilities, PageLoadStrategy } = ChromeUtils.import(
|
||||
"chrome://marionette/content/capabilities.js"
|
||||
);
|
||||
const { capture } = ChromeUtils.import(
|
||||
"chrome://marionette/content/capture.js"
|
||||
);
|
||||
const { element, WebElement } = ChromeUtils.import(
|
||||
"chrome://marionette/content/element.js"
|
||||
);
|
||||
|
@ -545,6 +542,7 @@ let getElementPropertyFn = dispatch(getElementProperty);
|
|||
let getElementTextFn = dispatch(getElementText);
|
||||
let getElementTagNameFn = dispatch(getElementTagName);
|
||||
let getElementRectFn = dispatch(getElementRect);
|
||||
let getScreenshotRectFn = dispatch(getScreenshotRect);
|
||||
let isElementEnabledFn = dispatch(isElementEnabled);
|
||||
let findElementContentFn = dispatch(findElementContent);
|
||||
let findElementsContentFn = dispatch(findElementsContent);
|
||||
|
@ -554,7 +552,6 @@ let isElementDisplayedFn = dispatch(isElementDisplayed);
|
|||
let getElementValueOfCssPropertyFn = dispatch(getElementValueOfCssProperty);
|
||||
let switchToShadowRootFn = dispatch(switchToShadowRoot);
|
||||
let singleTapFn = dispatch(singleTap);
|
||||
let takeScreenshotFn = dispatch(takeScreenshot);
|
||||
let performActionsFn = dispatch(performActions);
|
||||
let releaseActionsFn = dispatch(releaseActions);
|
||||
let actionChainFn = dispatch(actionChain);
|
||||
|
@ -591,6 +588,7 @@ function startListeners() {
|
|||
);
|
||||
addMessageListener("Marionette:get", get);
|
||||
addMessageListener("Marionette:getPageSource", getPageSourceFn);
|
||||
addMessageListener("Marionette:getScreenshotRect", getScreenshotRectFn);
|
||||
addMessageListener("Marionette:goBack", goBack);
|
||||
addMessageListener("Marionette:goForward", goForward);
|
||||
addMessageListener("Marionette:isElementDisplayed", isElementDisplayedFn);
|
||||
|
@ -607,7 +605,6 @@ function startListeners() {
|
|||
addMessageListener("Marionette:switchToFrame", switchToFrame);
|
||||
addMessageListener("Marionette:switchToParentFrame", switchToParentFrame);
|
||||
addMessageListener("Marionette:switchToShadowRoot", switchToShadowRootFn);
|
||||
addMessageListener("Marionette:takeScreenshot", takeScreenshotFn);
|
||||
addMessageListener("Marionette:waitForPageLoaded", waitForPageLoaded);
|
||||
}
|
||||
|
||||
|
@ -639,6 +636,7 @@ function deregister() {
|
|||
);
|
||||
removeMessageListener("Marionette:get", get);
|
||||
removeMessageListener("Marionette:getPageSource", getPageSourceFn);
|
||||
removeMessageListener("Marionette:getScreenshotRect", getScreenshotRectFn);
|
||||
removeMessageListener("Marionette:goBack", goBack);
|
||||
removeMessageListener("Marionette:goForward", goForward);
|
||||
removeMessageListener("Marionette:isElementDisplayed", isElementDisplayedFn);
|
||||
|
@ -654,7 +652,6 @@ function deregister() {
|
|||
removeMessageListener("Marionette:switchToFrame", switchToFrame);
|
||||
removeMessageListener("Marionette:switchToParentFrame", switchToParentFrame);
|
||||
removeMessageListener("Marionette:switchToShadowRoot", switchToShadowRootFn);
|
||||
removeMessageListener("Marionette:takeScreenshot", takeScreenshotFn);
|
||||
removeMessageListener("Marionette:waitForPageLoaded", waitForPageLoaded);
|
||||
}
|
||||
|
||||
|
@ -1627,7 +1624,15 @@ function switchToFrame(msg) {
|
|||
}
|
||||
|
||||
/**
|
||||
* Perform a screen capture in content context.
|
||||
* Returns the rect of the element to screenshot.
|
||||
*
|
||||
* Because the screen capture takes place in the parent process the dimensions
|
||||
* for the screenshot have to be determined in the appropriate child process.
|
||||
*
|
||||
* Also it takes care of scrolling an element into view if requested.
|
||||
*
|
||||
* @param {Object.<string, ?>} opts
|
||||
* Options.
|
||||
*
|
||||
* Accepted values for |opts|:
|
||||
*
|
||||
|
@ -1644,44 +1649,35 @@ function switchToFrame(msg) {
|
|||
* @param {Object.<string, ?>} opts
|
||||
* Options.
|
||||
*
|
||||
* @return {string}
|
||||
* Base64 encoded string or a SHA-256 hash of the screenshot.
|
||||
* @return {DOMRect}
|
||||
* The area to take a snapshot from
|
||||
*/
|
||||
function takeScreenshot(format, { id, full = true, scroll = true } = {}) {
|
||||
function getScreenshotRect({ id, full = true, scroll = true } = {}) {
|
||||
let win = curContainer.frame;
|
||||
|
||||
let canvas;
|
||||
let rect;
|
||||
|
||||
// element or full document element
|
||||
if (id || full) {
|
||||
let el;
|
||||
if (id) {
|
||||
let webEl = WebElement.fromUUID(id, "content");
|
||||
el = seenEls.get(webEl, win);
|
||||
if (scroll) {
|
||||
element.scrollIntoView(el);
|
||||
}
|
||||
} else {
|
||||
el = win.document.documentElement;
|
||||
if (id) {
|
||||
let webEl = WebElement.fromUUID(id, "content");
|
||||
let el = seenEls.get(webEl, win);
|
||||
if (scroll) {
|
||||
element.scrollIntoView(el);
|
||||
}
|
||||
|
||||
canvas = capture.element(el);
|
||||
|
||||
// viewport
|
||||
rect = el.getBoundingClientRect();
|
||||
} else if (full) {
|
||||
let clientRect = win.document.documentElement.getBoundingClientRect();
|
||||
rect = new DOMRect(0, 0, clientRect.width, clientRect.height);
|
||||
} else {
|
||||
canvas = capture.viewport(win);
|
||||
// viewport
|
||||
rect = new DOMRect(
|
||||
win.pageXOffset,
|
||||
win.pageYOffset,
|
||||
win.innerWidth,
|
||||
win.innerHeight
|
||||
);
|
||||
}
|
||||
|
||||
switch (format) {
|
||||
case capture.Format.Base64:
|
||||
return capture.toBase64(canvas);
|
||||
|
||||
case capture.Format.Hash:
|
||||
return capture.toHash(canvas);
|
||||
|
||||
default:
|
||||
throw new TypeError("Unknown screenshot format: " + format);
|
||||
}
|
||||
return rect;
|
||||
}
|
||||
|
||||
function flushRendering() {
|
||||
|
|
Загрузка…
Ссылка в новой задаче