1 /* 2 * Copyright (C) 2006 Nikolas Zimmermann <zimmermann (at) kde.org> 3 * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies) 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of 15 * its contributors may be used to endorse or promote products derived 16 * from this software without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY 19 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 20 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY 22 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 23 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 24 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 25 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 */ 29 30 #include "DumpRenderTreeQt.h" 31 32 #include <wtf/AlwaysInline.h> 33 34 #include <qstringlist.h> 35 #include <qapplication.h> 36 #include <qurl.h> 37 #include <qdir.h> 38 #include <qdebug.h> 39 #include <qfont.h> 40 #include <qwebdatabase.h> 41 #include <qtimer.h> 42 #include <qwindowsstyle.h> 43 44 #ifdef Q_WS_X11 45 #include <qx11info_x11.h> 46 #include <fontconfig/fontconfig.h> 47 #endif 48 49 #ifdef Q_OS_WIN 50 #include <io.h> 51 #include <fcntl.h> 52 #endif 53 54 #include <limits.h> 55 #include <signal.h> 56 57 #if defined(__GLIBC__) && !defined(__UCLIBC__) 58 #include <execinfo.h> 59 #endif 60 61 void messageHandler(QtMsgType type, const char *message) 62 { 63 if (type == QtCriticalMsg) { 64 fprintf(stderr, "%s\n", message); 65 return; 66 } 67 // do nothing 68 } 69 70 // We only support -v or --pixel-tests or --stdout or --stderr or -, all the others will be 71 // pass as test case name (even -abc.html is a valid test case name) 72 bool isOption(const QString& str) 73 { 74 return str == QString("-v") || str == QString("--pixel-tests") 75 || str == QString("--stdout") || str == QString("--stderr") 76 || str == QString("-"); 77 } 78 79 QString takeOptionValue(QStringList& arguments, int index) 80 { 81 QString result; 82 83 if (index + 1 < arguments.count() && !isOption(arguments.at(index + 1))) 84 result = arguments.takeAt(index + 1); 85 arguments.removeAt(index); 86 87 return result; 88 } 89 90 void printUsage() 91 { 92 fprintf(stderr, "Usage: DumpRenderTree [-v|--pixel-tests] [--stdout output_filename] [-stderr error_filename] filename [filename2..n]\n"); 93 fprintf(stderr, "Or folder containing test files: DumpRenderTree [-v|--pixel-tests] dirpath\n"); 94 fflush(stderr); 95 } 96 97 QString get_backtrace() { 98 QString s; 99 100 #if defined(__GLIBC__) && !defined(__UCLIBC__) 101 void* array[256]; 102 size_t size; /* number of stack frames */ 103 104 size = backtrace(array, 256); 105 106 if (!size) 107 return s; 108 109 char** strings = backtrace_symbols(array, size); 110 for (int i = 0; i < int(size); ++i) { 111 s += QString::number(i) + 112 QLatin1String(": ") + 113 QLatin1String(strings[i]) + QLatin1String("\n"); 114 } 115 116 if (strings) 117 free (strings); 118 #endif 119 120 return s; 121 } 122 123 #if HAVE(SIGNAL_H) 124 static NO_RETURN void crashHandler(int sig) 125 { 126 fprintf(stderr, "%s\n", strsignal(sig)); 127 fprintf(stderr, "%s\n", get_backtrace().toLatin1().constData()); 128 exit(128 + sig); 129 } 130 #endif 131 132 int main(int argc, char* argv[]) 133 { 134 #ifdef Q_OS_WIN 135 _setmode(1, _O_BINARY); 136 _setmode(2, _O_BINARY); 137 #endif 138 139 #ifdef Q_WS_X11 140 FcInit(); 141 WebCore::DumpRenderTree::initializeFonts(); 142 #endif 143 144 QApplication::setGraphicsSystem("raster"); 145 QApplication::setStyle(new QWindowsStyle); 146 147 QFont f("Sans Serif"); 148 f.setPointSize(9); 149 f.setWeight(QFont::Normal); 150 f.setStyle(QFont::StyleNormal); 151 QApplication::setFont(f); 152 153 QApplication app(argc, argv); 154 #ifdef Q_WS_X11 155 QX11Info::setAppDpiY(0, 96); 156 QX11Info::setAppDpiX(0, 96); 157 #endif 158 159 #if HAVE(SIGNAL_H) 160 signal(SIGILL, crashHandler); /* 4: illegal instruction (not reset when caught) */ 161 signal(SIGTRAP, crashHandler); /* 5: trace trap (not reset when caught) */ 162 signal(SIGFPE, crashHandler); /* 8: floating point exception */ 163 signal(SIGBUS, crashHandler); /* 10: bus error */ 164 signal(SIGSEGV, crashHandler); /* 11: segmentation violation */ 165 signal(SIGSYS, crashHandler); /* 12: bad argument to system call */ 166 signal(SIGPIPE, crashHandler); /* 13: write on a pipe with no reader */ 167 signal(SIGXCPU, crashHandler); /* 24: exceeded CPU time limit */ 168 signal(SIGXFSZ, crashHandler); /* 25: exceeded file size limit */ 169 #endif 170 171 QStringList args = app.arguments(); 172 if (args.count() < 2) { 173 printUsage(); 174 exit(1); 175 } 176 177 // Remove the first arguments, it is application name itself 178 args.removeAt(0); 179 180 // Suppress debug output from Qt if not started with -v 181 int index = args.indexOf(QLatin1String("-v")); 182 if (index == -1) 183 qInstallMsgHandler(messageHandler); 184 else 185 args.removeAt(index); 186 187 WebCore::DumpRenderTree dumper; 188 189 index = args.indexOf(QLatin1String("--pixel-tests")); 190 if (index != -1) { 191 dumper.setDumpPixels(true); 192 args.removeAt(index); 193 } 194 195 index = args.indexOf(QLatin1String("--stdout")); 196 if (index != -1) { 197 QString fileName = takeOptionValue(args, index); 198 dumper.setRedirectOutputFileName(fileName); 199 if (fileName.isEmpty() || !freopen(qPrintable(fileName), "w", stdout)) { 200 fprintf(stderr, "STDOUT redirection failed."); 201 exit(1); 202 } 203 } 204 index = args.indexOf(QLatin1String("--stderr")); 205 if (index != -1) { 206 QString fileName = takeOptionValue(args, index); 207 dumper.setRedirectErrorFileName(fileName); 208 if (!freopen(qPrintable(fileName), "w", stderr)) { 209 fprintf(stderr, "STDERR redirection failed."); 210 exit(1); 211 } 212 } 213 QWebDatabase::removeAllDatabases(); 214 215 index = args.indexOf(QLatin1String("-")); 216 if (index != -1) { 217 args.removeAt(index); 218 219 // Continue waiting in STDIN for more test case after process one test case 220 QObject::connect(&dumper, SIGNAL(ready()), &dumper, SLOT(readLine()), Qt::QueuedConnection); 221 222 // Read and only read the first test case, ignore the others 223 if (args.size() > 0) { 224 // Process the argument first 225 dumper.processLine(args[0]); 226 } else 227 QTimer::singleShot(0, &dumper, SLOT(readLine())); 228 } else { 229 // Go into standalone mode 230 // Standalone mode need at least one test case 231 if (args.count() < 1) { 232 printUsage(); 233 exit(1); 234 } 235 dumper.processArgsLine(args); 236 } 237 return app.exec(); 238 239 #ifdef Q_WS_X11 240 FcConfigSetCurrent(0); 241 #endif 242 } 243