1 /* 2 * Copyright (C) 2010 Google Inc. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions are 6 * met: 7 * 8 * * Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * * Redistributions in binary form must reproduce the above 11 * copyright notice, this list of conditions and the following disclaimer 12 * in the documentation and/or other materials provided with the 13 * distribution. 14 * * Neither the name of Google Inc. nor the names of its 15 * contributors may be used to endorse or promote products derived from 16 * this software without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 */ 30 31 #include "config.h" 32 #include "TestShell.h" 33 34 #include "WebThemeEngineDRTWin.h" 35 #include "webkit/support/webkit_support.h" 36 #include <fcntl.h> 37 #include <io.h> 38 #include <list> 39 #include <process.h> 40 #include <shlwapi.h> 41 #include <string> 42 #include <sys/stat.h> 43 #include <windows.h> 44 45 #define SIZEOF_STRUCT_WITH_SPECIFIED_LAST_MEMBER(structName, member) \ 46 offsetof(structName, member) + \ 47 (sizeof static_cast<structName*>(0)->member) 48 #define NONCLIENTMETRICS_SIZE_PRE_VISTA \ 49 SIZEOF_STRUCT_WITH_SPECIFIED_LAST_MEMBER(NONCLIENTMETRICS, lfMessageFont) 50 51 // Theme engine 52 static WebThemeEngineDRTWin themeEngine; 53 54 // Thread main to run for the thread which just tests for timeout. 55 unsigned int __stdcall watchDogThread(void* arg) 56 { 57 // If we're debugging a layout test, don't timeout. 58 if (::IsDebuggerPresent()) 59 return 0; 60 61 TestShell* shell = static_cast<TestShell*>(arg); 62 // FIXME: Do we need user-specified time settings as with the original 63 // Chromium implementation? 64 DWORD timeout = static_cast<DWORD>(shell->layoutTestTimeoutForWatchDog()); 65 DWORD rv = WaitForSingleObject(shell->finishedEvent(), timeout); 66 if (rv == WAIT_TIMEOUT) { 67 // Print a warning to be caught by the layout-test script. 68 // Note: the layout test driver may or may not recognize 69 // this as a timeout. 70 puts("\n#TEST_TIMED_OUT\n"); 71 puts("#EOF\n"); 72 fflush(stdout); 73 TerminateProcess(GetCurrentProcess(), 0); 74 } 75 // Finished normally. 76 return 0; 77 } 78 79 void TestShell::waitTestFinished() 80 { 81 DCHECK(!m_testIsPending) << "cannot be used recursively"; 82 83 m_testIsPending = true; 84 85 // Create a watchdog thread which just sets a timer and 86 // kills the process if it times out. This catches really 87 // bad hangs where the shell isn't coming back to the 88 // message loop. If the watchdog is what catches a 89 // timeout, it can't do anything except terminate the test 90 // shell, which is unfortunate. 91 m_finishedEvent = CreateEvent(0, TRUE, FALSE, 0); 92 DCHECK(m_finishedEvent); 93 94 HANDLE threadHandle = reinterpret_cast<HANDLE>(_beginthreadex( 95 0, 96 0, 97 &watchDogThread, 98 this, 99 0, 100 0)); 101 DCHECK(threadHandle); 102 103 // TestFinished() will post a quit message to break this loop when the page 104 // finishes loading. 105 while (m_testIsPending) 106 webkit_support::RunMessageLoop(); 107 108 // Tell the watchdog that we are finished. 109 SetEvent(m_finishedEvent); 110 111 // Wait to join the watchdog thread. (up to 1s, then quit) 112 WaitForSingleObject(threadHandle, 1000); 113 } 114 115 void platformInit(int*, char***) 116 { 117 // Set stdout/stderr binary mode. 118 _setmode(_fileno(stdout), _O_BINARY); 119 _setmode(_fileno(stderr), _O_BINARY); 120 121 // Set theme engine. 122 webkit_support::SetThemeEngine(&themeEngine); 123 124 // Load Ahem font. 125 // AHEM____.TTF is copied to the directory of DumpRenderTree.exe by WebKit.gyp. 126 WCHAR path[_MAX_PATH]; 127 if (!::GetModuleFileName(0, path, _MAX_PATH)) { 128 fprintf(stderr, "Can't get the module path.\n"); 129 exit(1); 130 } 131 ::PathRemoveFileSpec(path); 132 wcscat_s(path, _MAX_PATH, L"/AHEM____.TTF"); 133 struct _stat ahemStat; 134 if (_wstat(path, &ahemStat) == -1) { 135 fprintf(stderr, "Can't access: '%S'\n", path); 136 exit(1); 137 } 138 139 FILE* fp = _wfopen(path, L"rb"); 140 if (!fp) { 141 _wperror(path); 142 exit(1); 143 } 144 size_t size = ahemStat.st_size; 145 char* fontBuffer = new char[size]; 146 if (fread(fontBuffer, 1, size, fp) != size) { 147 fprintf(stderr, "Can't read the font: '%S'\n", path); 148 fclose(fp); 149 exit(1); 150 } 151 fclose(fp); 152 DWORD numFonts = 1; 153 HANDLE fontHandle = ::AddFontMemResourceEx(fontBuffer, size, 0, &numFonts); 154 delete[] fontBuffer; // OS owns a copy of the buffer. 155 if (!fontHandle) { 156 fprintf(stderr, "Failed to register Ahem font: '%S'\n", path); 157 exit(1); 158 } 159 // We don't need to release the font explicitly. 160 } 161 162 void openStartupDialog() 163 { 164 ::MessageBox(0, L"Attach to me?", L"DumpRenderTree", MB_OK); 165 } 166 167 bool checkLayoutTestSystemDependencies() 168 { 169 // This metric will be 17 when font size is "Normal". 170 // The size of drop-down menus depends on it. 171 int verticalScrollSize = ::GetSystemMetrics(SM_CXVSCROLL); 172 int requiredVScrollSize = 17; 173 std::list<std::string> errors; 174 if (verticalScrollSize != requiredVScrollSize) 175 errors.push_back("Must use normal size fonts (96 dpi)."); 176 177 // ClearType must be disabled, because the rendering is unpredictable. 178 BOOL fontSmoothingEnabled; 179 ::SystemParametersInfo(SPI_GETFONTSMOOTHING, 0, &fontSmoothingEnabled, 0); 180 int fontSmoothingType; 181 ::SystemParametersInfo(SPI_GETFONTSMOOTHINGTYPE, 0, &fontSmoothingType, 0); 182 if (fontSmoothingEnabled && (fontSmoothingType == FE_FONTSMOOTHINGCLEARTYPE)) 183 errors.push_back("ClearType must be disabled."); 184 185 // Check that we're using the default system fonts. 186 OSVERSIONINFO versionInfo = {0}; 187 versionInfo.dwOSVersionInfoSize = sizeof(versionInfo); 188 ::GetVersionEx(&versionInfo); 189 const bool isVistaOrLater = (versionInfo.dwMajorVersion >= 6); 190 NONCLIENTMETRICS metrics = {0}; 191 metrics.cbSize = isVistaOrLater ? (sizeof NONCLIENTMETRICS) : NONCLIENTMETRICS_SIZE_PRE_VISTA; 192 const bool success = !!::SystemParametersInfo(SPI_GETNONCLIENTMETRICS, metrics.cbSize, &metrics, 0); 193 ASSERT(success); 194 LOGFONTW* systemFonts[] = 195 {&metrics.lfStatusFont, &metrics.lfMenuFont, &metrics.lfSmCaptionFont}; 196 const wchar_t* const requiredFont = isVistaOrLater ? L"Segoe UI" : L"Tahoma"; 197 const int requiredFontSize = isVistaOrLater ? -12 : -11; 198 for (size_t i = 0; i < arraysize(systemFonts); ++i) { 199 if (systemFonts[i]->lfHeight != requiredFontSize || wcscmp(requiredFont, systemFonts[i]->lfFaceName)) { 200 errors.push_back(isVistaOrLater ? "Must use either the Aero or Basic theme." : "Must use the default XP theme (Luna)."); 201 break; 202 } 203 } 204 205 if (!errors.empty()) { 206 fprintf(stderr, "%s", 207 "##################################################################\n" 208 "## Layout test system dependencies check failed.\n" 209 "##\n"); 210 for (std::list<std::string>::iterator it = errors.begin(); it != errors.end(); ++it) 211 fprintf(stderr, "## %s\n", it->c_str()); 212 fprintf(stderr, "%s", 213 "##\n" 214 "##################################################################\n"); 215 } 216 return errors.empty(); 217 } 218