From 8d56be189cad39e719a35c53b07d65c8fc627aa6 Mon Sep 17 00:00:00 2001 From: Dave Hunt Date: Tue, 30 Sep 2014 14:42:00 -0400 Subject: [PATCH] Bug 883294 - Add ability to take full viewport screenshots. r=mdas --- .../marionette/runner/mixins/reporting.py | 4 +- .../marionette/tests/unit/test_screenshot.py | 25 +++++-- testing/marionette/marionette-server.js | 68 +++++++++++++++---- 3 files changed, 78 insertions(+), 19 deletions(-) diff --git a/testing/marionette/client/marionette/runner/mixins/reporting.py b/testing/marionette/client/marionette/runner/mixins/reporting.py index 0215dba3e445..4ad572f7454d 100644 --- a/testing/marionette/client/marionette/runner/mixins/reporting.py +++ b/testing/marionette/client/marionette/runner/mixins/reporting.py @@ -246,9 +246,9 @@ class HTMLReportingTestResultMixin(object): def gather_debug(self): debug = {} try: - # TODO make screenshot consistant size by using full viewport - # Bug 883294 - Add ability to take full viewport screenshots + self.marionette.switch_context(self.marionette.CONTEXT_CHROME) debug['screenshot'] = self.marionette.screenshot() + self.marionette.switch_context(self.marionette.CONTEXT_CONTENT) debug['source'] = self.marionette.page_source self.marionette.switch_to_frame() debug['settings'] = json.dumps(self.marionette.execute_async_script(""" diff --git a/testing/marionette/client/marionette/tests/unit/test_screenshot.py b/testing/marionette/client/marionette/tests/unit/test_screenshot.py index b6ab6434cfbb..38e2d74bc43a 100644 --- a/testing/marionette/client/marionette/tests/unit/test_screenshot.py +++ b/testing/marionette/client/marionette/tests/unit/test_screenshot.py @@ -1,11 +1,25 @@ -from marionette_test import MarionetteTestCase import base64 +import imghdr + +from marionette_test import MarionetteTestCase + RED_ELEMENT_BASE64 = 'iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAAAVUlEQVRoge3PsQ0AIAzAsI78fzBwBhHykD2ePev80LweAAGJB1ILpBZILZBaILVAaoHUAqkFUgukFkgtkFogtUBqgdQCqQVSC6QWSC2QWiC1QGp9A7ma+7nyXgOpzQAAAABJRU5ErkJggg==' GREEN_ELEMENT_BASE64 = 'iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAAAV0lEQVRoge3PQRGAQAwAsWINvXgsNnI3+4iAzM7sDWZn9vneoxXRFNEU0RTRFNEU0RTRFNEU0RTRFNEU0RTRFNEU0RTRFNEU0RTRFNEU0RTRFNHcF7nBD/Ha5Ye4BbsYAAAAAElFTkSuQmCC' class ScreenshotTests(MarionetteTestCase): + def testWeCanTakeAScreenShotOfEntireViewport(self): + test_url = self.marionette.absolute_url('html5Page.html') + self.marionette.navigate(test_url) + content = self.marionette.screenshot() + self.marionette.set_context(self.marionette.CONTEXT_CHROME) + chrome = self.marionette.screenshot() + # Check the base64 decoded string is a PNG file. + image = base64.decodestring(chrome) + self.assertEqual(imghdr.what('', image), 'png') + self.assertNotEqual(content, chrome) + def testWeCanTakeAScreenShotOfAnElement(self): test_url = self.marionette.absolute_url('html5Page.html') self.marionette.navigate(test_url) @@ -20,11 +34,12 @@ class ScreenshotTests(MarionetteTestCase): self.assertEqual(GREEN_ELEMENT_BASE64, self.marionette.screenshot(element=el, highlights=[el])) - def testWeCanTakeAScreenShotEntireCanvas(self): + def testWeCanTakeAScreenShotOfEntireCanvas(self): test_url = self.marionette.absolute_url('html5Page.html') self.marionette.navigate(test_url) - self.assertTrue('iVBORw0KGgo' in - self.marionette.screenshot()) + # Check the base64 decoded string is a PNG file. + image = base64.decodestring(self.marionette.screenshot()) + self.assertEqual(imghdr.what('', image), 'png') def testWeCanTakeABinaryScreenShotOfAnElement(self): test_url = self.marionette.absolute_url('html5Page.html') @@ -33,7 +48,7 @@ class ScreenshotTests(MarionetteTestCase): binary_data = self.marionette.screenshot(element=el, format="binary") self.assertEqual(RED_ELEMENT_BASE64, base64.b64encode(binary_data)) - + def testNotAllowedScreenshotFormatRaiseValueError(self): test_url = self.marionette.absolute_url('html5Page.html') self.marionette.navigate(test_url) diff --git a/testing/marionette/marionette-server.js b/testing/marionette/marionette-server.js index d93bf8d9f6d4..4218bc01ff9d 100644 --- a/testing/marionette/marionette-server.js +++ b/testing/marionette/marionette-server.js @@ -2371,26 +2371,70 @@ MarionetteServerConnection.prototype = { }, /** - * Takes a screenshot of a web element or the current frame. + * Takes a screenshot of a web element, current frame, or viewport. * * The screen capture is returned as a lossless PNG image encoded as - * a base 64 string. If the id argument is not null - * and refers to a present and visible web element's ID, the capture - * area will be limited to the bounding box of that element. - * Otherwise, the capture area will be the bounding box of the - * current frame. + * a base 64 string. * - * @param id an optional reference to a web element - * @param highlights an optional list of web elements to draw a red - * box around in the returned capture - * @return PNG image encoded as base 64 string - */ + * If called in the content context, the id argument is not null + * and refers to a present and visible web element's ID, the capture area + * will be limited to the bounding box of that element. Otherwise, the + * capture area will be the bounding box of the current frame. + * + * If called in the chrome context, the screenshot will always represent the + * entire viewport. + * + * @param {string} [id] Reference to a web element. + * @param {string} [highlights] List of web elements to highlight. + * @return {string} PNG image encoded as base 64 string. + */ takeScreenshot: function MDA_takeScreenshot(aRequest) { this.command_id = this.getCommandId(); - this.sendAsync("takeScreenshot", + if (this.context == "chrome") { + var win = this.getCurrentWindow(); + var canvas = win.document.createElementNS("http://www.w3.org/1999/xhtml", "canvas"); + var doc; + if (appName == "B2G") { + doc = win.document.body; + } else { + doc = win.document.getElementsByTagName('window')[0]; + } + var docRect = doc.getBoundingClientRect(); + var width = docRect.width; + var height = docRect.height; + + // Convert width and height from CSS pixels (potentially fractional) + // to device pixels (integer). + var scale = win.devicePixelRatio; + canvas.setAttribute("width", Math.round(width * scale)); + canvas.setAttribute("height", Math.round(height * scale)); + + var context = canvas.getContext("2d"); + var flags; + if (appName == "B2G") { + flags = + context.DRAWWINDOW_DRAW_CARET | + context.DRAWWINDOW_DRAW_VIEW | + context.DRAWWINDOW_USE_WIDGET_LAYERS; + } else { + // Bug 1075168 - CanvasRenderingContext2D image is distorted + // when using certain flags in chrome context. + flags = + context.DRAWWINDOW_DRAW_VIEW | + context.DRAWWINDOW_USE_WIDGET_LAYERS; + } + context.scale(scale, scale); + context.drawWindow(win, 0, 0, width, height, "rgb(255,255,255)", flags); + var dataUrl = canvas.toDataURL("image/png", ""); + var data = dataUrl.substring(dataUrl.indexOf(",") + 1); + this.sendResponse(data, this.command_id); + } + else { + this.sendAsync("takeScreenshot", {id: aRequest.parameters.id, highlights: aRequest.parameters.highlights}, this.command_id); + } }, /**