From 80710b8eead3072a61eec6c37632f9d10c2a9a74 Mon Sep 17 00:00:00 2001 From: Gavin Sharp Date: Wed, 8 Feb 2012 12:30:07 -0800 Subject: [PATCH] Bug 589668: take screenshots on test failures on Windows, screenshot utility written by Ted Mielczarek , build goop by me and jhford, r=khuey --HG-- extra : transplant_source : %2A%07%B3w%DEg%DB%99%7EQR8Wq/%96J%E8%8D%D8 --- build/automation.py.in | 6 +- testing/mochitest/Makefile.in | 4 + testing/tools/screenshot/Makefile.in | 9 ++ testing/tools/screenshot/win32-screenshot.cpp | 115 ++++++++++++++++++ 4 files changed, 131 insertions(+), 3 deletions(-) create mode 100644 testing/tools/screenshot/win32-screenshot.cpp diff --git a/build/automation.py.in b/build/automation.py.in index 5b4a5272aed9..a376074be160 100644 --- a/build/automation.py.in +++ b/build/automation.py.in @@ -700,8 +700,8 @@ user_pref("camino.use_system_proxy_settings", false); // Camino-only, harmless t utility = ['/usr/sbin/screencapture', '-C', '-x', '-t', 'png'] imgoutput = 'file' elif self.IS_WIN32: - self.log.info("If you fixed bug 589668, you'd get a screenshot here") - return + utility = [os.path.join(utilityPath, "screenshot.exe")] + imgoutput = 'file' # Run the capture correctly for the type of capture try: @@ -727,7 +727,7 @@ user_pref("camino.use_system_proxy_settings", false); // Camino-only, harmless t if imgoutput == 'stdout': image = dumper_out elif imgoutput == 'file': - with open(imgfilename) as imgfile: + with open(imgfilename, 'rb') as imgfile: image = imgfile.read() except IOError, err: self.log.info("Failed to read image from %s", imgoutput) diff --git a/testing/mochitest/Makefile.in b/testing/mochitest/Makefile.in index 0940c725600a..dcd6c1112963 100644 --- a/testing/mochitest/Makefile.in +++ b/testing/mochitest/Makefile.in @@ -183,6 +183,10 @@ ifeq (gtk2_1,$(MOZ_WIDGET_TOOLKIT)_$(MOZ_X11)) TEST_HARNESS_BINS += screentopng endif +ifeq (windows,$(MOZ_WIDGET_TOOLKIT)) +TEST_HARNESS_BINS += screenshot$(BIN_SUFFIX) +endif + # Components / typelibs that don't get packaged with # the build, but that we need for the test harness. TEST_HARNESS_COMPONENTS := \ diff --git a/testing/tools/screenshot/Makefile.in b/testing/tools/screenshot/Makefile.in index 6ca564d2d4b7..cacb56f4aed9 100644 --- a/testing/tools/screenshot/Makefile.in +++ b/testing/tools/screenshot/Makefile.in @@ -53,4 +53,13 @@ OS_LIBS = $(MOZ_GTK2_LIBS) $(XSS_LIBS) endif # X11 endif # GTK2 +ifeq ($(MOZ_WIDGET_TOOLKIT),windows) + +PROGRAM = screenshot$(BIN_SUFFIX) +CPPSRCS = win32-screenshot.cpp +MOZ_GLUE_PROGRAM_LDFLAGS = +USE_STATIC_LIBS = 1 + +endif # windows + include $(topsrcdir)/config/rules.mk diff --git a/testing/tools/screenshot/win32-screenshot.cpp b/testing/tools/screenshot/win32-screenshot.cpp new file mode 100644 index 000000000000..691768242f56 --- /dev/null +++ b/testing/tools/screenshot/win32-screenshot.cpp @@ -0,0 +1,115 @@ +/* + * Copyright (c) 2009, The Mozilla Foundation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the Mozilla Foundation nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY The Mozilla Foundation ''AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL The Mozilla Foundation BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Contributors: + * Ted Mielczarek + */ +/* + * screenshot.cpp : Save a screenshot of the Windows desktop in .png format. + * If a filename is specified as the first argument on the commandline, + * then the image will be saved to that filename. Otherwise, the image will + * be saved as "screenshot.png" in the current working directory. + * + * Requires GDI+. All linker dependencies are specified explicitly in this + * file, so you can compile screenshot.exe by simply running: + * cl screenshot.cpp + */ + +#undef WIN32_LEAN_AND_MEAN +#include +#include + +#pragma comment(lib, "user32.lib") +#pragma comment(lib, "gdi32.lib") +#pragma comment(lib, "gdiplus.lib") + +using namespace Gdiplus; + +// From http://msdn.microsoft.com/en-us/library/ms533843%28VS.85%29.aspx +int GetEncoderClsid(const WCHAR* format, CLSID* pClsid) +{ + UINT num = 0; // number of image encoders + UINT size = 0; // size of the image encoder array in bytes + + ImageCodecInfo* pImageCodecInfo = NULL; + + GetImageEncodersSize(&num, &size); + if(size == 0) + return -1; // Failure + + pImageCodecInfo = (ImageCodecInfo*)(malloc(size)); + if(pImageCodecInfo == NULL) + return -1; // Failure + + GetImageEncoders(num, size, pImageCodecInfo); + + for(UINT j = 0; j < num; ++j) + { + if( wcscmp(pImageCodecInfo[j].MimeType, format) == 0 ) + { + *pClsid = pImageCodecInfo[j].Clsid; + free(pImageCodecInfo); + return j; // Success + } + } + + free(pImageCodecInfo); + return -1; // Failure +} + +int wmain(int argc, wchar_t** argv) +{ + GdiplusStartupInput gdiplusStartupInput; + ULONG_PTR gdiplusToken; + GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL); + + HWND desktop = GetDesktopWindow(); + HDC desktopdc = GetDC(desktop); + HDC mydc = CreateCompatibleDC(desktopdc); + int width = GetSystemMetrics(SM_CXSCREEN); + int height = GetSystemMetrics(SM_CYSCREEN); + HBITMAP mybmp = CreateCompatibleBitmap(desktopdc, width, height); + HBITMAP oldbmp = (HBITMAP)SelectObject(mydc, mybmp); + BitBlt(mydc,0,0,width,height,desktopdc,0,0, SRCCOPY|CAPTUREBLT); + SelectObject(mydc, oldbmp); + + const wchar_t* filename = (argc > 1) ? argv[1] : L"screenshot.png"; + Bitmap* b = Bitmap::FromHBITMAP(mybmp, NULL); + CLSID encoderClsid; + Status stat = GenericError; + if (b && GetEncoderClsid(L"image/png", &encoderClsid) != -1) { + stat = b->Save(filename, &encoderClsid, NULL); + } + if (b) + delete b; + + // cleanup + GdiplusShutdown(gdiplusToken); + ReleaseDC(desktop, desktopdc); + DeleteObject(mybmp); + DeleteDC(mydc); + return stat == Ok ? 0 : 1; +}