Bug 810259: Adding support for getting screenshot from Marionette; r=mdas

This commit is contained in:
David Burns 2012-11-30 23:25:26 +00:00
parent 07aab17c73
commit c93c8514aa
5 changed files with 119 additions and 2 deletions

View File

@ -498,3 +498,8 @@ class Marionette(object):
@property
def application_cache(self):
return ApplicationCache(self)
def screenshot(self, element=None, highlights=None):
if element is not None:
element = element.id
return self._send_message("screenShot", 'value', element=element, highlights=highlights)

View File

@ -0,0 +1,18 @@
from marionette_test import MarionetteTestCase
class ScreenshotTests(MarionetteTestCase):
def testWeCanTakeAScreenShotOfAnElement(self):
test_url = self.marionette.absolute_url('html5Page.html')
self.marionette.navigate(test_url)
el = self.marionette.find_element('id', 'red')
self.assertEqual('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAAAVUlEQVRoge3PsQ0AIAzAsI78fzBwBhHykD2ePev80LweAAGJB1ILpBZILZBaILVAaoHUAqkFUgukFkgtkFogtUBqgdQCqQVSC6QWSC2QWiC1QGp9A7ma+7nyXgOpzQAAAABJRU5ErkJggg==',
self.marionette.screenshot(element=el))
def testWeCanTakeAScreenShotEntireCanvas(self):
test_url = self.marionette.absolute_url('html5Page.html')
self.marionette.navigate(test_url)
self.assertTrue('data:image/png;base64,iVBORw0KGgo' in
self.marionette.screenshot())

View File

@ -51,4 +51,4 @@ b2g = false
b2g = false
[test_appcache.py]
[test_screenshot.py]

View File

@ -1594,6 +1594,15 @@ MarionetteDriverActor.prototype = {
}
},
/**
* Takes a screenshot of a DOM node. If there is no node given a screenshot
* of the window will be taken.
*/
screenShot: function MDA_saveScreenshot(aRequest) {
this.sendAsync("screenShot", {element: aRequest.element,
highlights: aRequest.highlights});
},
/**
* Helper function to convert an outerWindowID into a UID that Marionette
* tracks.
@ -1771,7 +1780,8 @@ MarionetteDriverActor.prototype.requestTypes = {
"importScript": MarionetteDriverActor.prototype.importScript,
"getAppCacheStatus": MarionetteDriverActor.prototype.getAppCacheStatus,
"closeWindow": MarionetteDriverActor.prototype.closeWindow,
"setTestName": MarionetteDriverActor.prototype.setTestName
"setTestName": MarionetteDriverActor.prototype.setTestName,
"screenShot": MarionetteDriverActor.prototype.screenShot
};
/**

View File

@ -120,6 +120,7 @@ function startListeners() {
addMessageListenerId("Marionette:getAppCacheStatus", getAppCacheStatus);
addMessageListenerId("Marionette:setTestName", setTestName);
addMessageListenerId("Marionette:setState", setState);
addMessageListenerId("Marionette:screenShot", screenShot);
}
/**
@ -200,6 +201,7 @@ function deleteSession(msg) {
removeMessageListenerId("Marionette:getAppCacheStatus", getAppCacheStatus);
removeMessageListenerId("Marionette:setTestName", setTestName);
removeMessageListenerId("Marionette:setState", setState);
removeMessageListenerId("Marionette:screenShot", screenShot);
this.elementManager.reset();
// reset frame to the top-most frame
curWindow = content;
@ -944,6 +946,88 @@ function importScript(msg) {
sendOk();
}
/**
* Saves a screenshot and returns a Base64 string
*/
function screenShot(msg) {
let node = null;
if (msg.json.element) {
try {
node = elementManager.getKnownElement(msg.json.element, curWindow)
}
catch (e) {
sendResponse(e.message, e.code, e.stack);
return;
}
}
else {
node = curWindow;
}
let highlights = msg.json.highlights;
var document = curWindow.document;
var rect, win, width, height, left, top, needsOffset;
// node can be either a window or an arbitrary DOM node
if (node == curWindow) {
// node is a window
win = node;
width = win.innerWidth;
height = win.innerHeight;
top = 0;
left = 0;
// offset needed for highlights to take 'outerHeight' of window into account
needsOffset = true;
}
else {
// node is an arbitrary DOM node
win = node.ownerDocument.defaultView;
rect = node.getBoundingClientRect();
width = rect.width;
height = rect.height;
top = rect.top;
left = rect.left;
// offset for highlights not needed as they will be relative to this node
needsOffset = false;
}
var canvas = document.createElementNS("http://www.w3.org/1999/xhtml", "canvas");
canvas.width = width;
canvas.height = height;
var ctx = canvas.getContext("2d");
// Draws the DOM contents of the window to the canvas
ctx.drawWindow(win, left, top, width, height, 'rgb(255,255,255)');
// This section is for drawing a red rectangle around each element passed in via the highlights array
if (highlights) {
ctx.lineWidth = "2";
ctx.strokeStyle = "red";
ctx.save();
for (var i = 0; i < highlights.length; ++i) {
var elem = highlights[i];
rect = elem.getBoundingClientRect();
var offsetY = 0, offsetX = 0;
if (needsOffset) {
var offset = getChromeOffset(elem);
offsetX = offset.x;
offsetY = offset.y;
} else {
// Don't need to offset the window chrome, just make relative to containing node
offsetY = -top;
offsetX = -left;
}
// Draw the rectangle
ctx.strokeRect(rect.left + offsetX, rect.top + offsetY, rect.width, rect.height);
}
}
// Return the Base64 String back to the client bindings and they can manage
// saving the file to disk if it is required
sendResponse({value:canvas.toDataURL("image/png","")});
}
//call register self when we get loaded
registerSelf();