1 /* 2 * Copyright (C) 2005, 2006, 2007, 2008, 2009 Apple 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 6 * are met: 7 * 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of 14 * its contributors may be used to endorse or promote products derived 15 * from this software without specific prior written permission. 16 * 17 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY 18 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 19 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 20 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY 21 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 22 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 23 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 24 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 #include "config.h" 30 #include "DumpRenderTree.h" 31 32 #include "EditingDelegate.h" 33 #include "FrameLoadDelegate.h" 34 #include "HistoryDelegate.h" 35 #include "LayoutTestController.h" 36 #include "PixelDumpSupport.h" 37 #include "PolicyDelegate.h" 38 #include "ResourceLoadDelegate.h" 39 #include "UIDelegate.h" 40 #include "WorkQueueItem.h" 41 #include "WorkQueue.h" 42 43 #include <fcntl.h> 44 #include <io.h> 45 #include <math.h> 46 #include <pthread.h> 47 #include <shlwapi.h> 48 #include <stdio.h> 49 #include <string.h> 50 #include <tchar.h> 51 #include <wtf/RetainPtr.h> 52 #include <wtf/Vector.h> 53 #include <windows.h> 54 #include <CoreFoundation/CoreFoundation.h> 55 #include <JavaScriptCore/JavaScriptCore.h> 56 #include <WebKit/WebKit.h> 57 #include <WebKit/WebKitCOMAPI.h> 58 59 #if USE(CFNETWORK) 60 #include <CFNetwork/CFURLCachePriv.h> 61 #endif 62 63 #if USE(CFNETWORK) 64 #include <CFNetwork/CFHTTPCookiesPriv.h> 65 #endif 66 67 using namespace std; 68 69 #if !defined(NDEBUG) && (!defined(DEBUG_INTERNAL) || defined(DEBUG_ALL)) 70 const LPWSTR TestPluginDir = L"TestNetscapePlugin_Debug"; 71 #else 72 const LPWSTR TestPluginDir = L"TestNetscapePlugin"; 73 #endif 74 75 static LPCWSTR fontsEnvironmentVariable = L"WEBKIT_TESTFONTS"; 76 #define USE_MAC_FONTS 77 78 const LPCWSTR kDumpRenderTreeClassName = L"DumpRenderTreeWindow"; 79 80 static bool dumpTree = true; 81 static bool dumpPixels; 82 static bool dumpAllPixels; 83 static bool printSeparators; 84 static bool leakChecking = false; 85 static bool threaded = false; 86 static bool forceComplexText = false; 87 static RetainPtr<CFStringRef> persistentUserStyleSheetLocation; 88 89 volatile bool done; 90 // This is the topmost frame that is loading, during a given load, or nil when no load is 91 // in progress. Usually this is the same as the main frame, but not always. In the case 92 // where a frameset is loaded, and then new content is loaded into one of the child frames, 93 // that child frame is the "topmost frame that is loading". 94 IWebFrame* topLoadingFrame; // !nil iff a load is in progress 95 static COMPtr<IWebHistoryItem> prevTestBFItem; // current b/f item at the end of the previous test 96 PolicyDelegate* policyDelegate; 97 COMPtr<FrameLoadDelegate> sharedFrameLoadDelegate; 98 COMPtr<UIDelegate> sharedUIDelegate; 99 COMPtr<EditingDelegate> sharedEditingDelegate; 100 COMPtr<ResourceLoadDelegate> sharedResourceLoadDelegate; 101 COMPtr<HistoryDelegate> sharedHistoryDelegate; 102 103 IWebFrame* frame; 104 HWND webViewWindow; 105 106 LayoutTestController* gLayoutTestController = 0; 107 108 UINT_PTR waitToDumpWatchdog = 0; 109 110 const unsigned maxViewWidth = 800; 111 const unsigned maxViewHeight = 600; 112 113 void setPersistentUserStyleSheetLocation(CFStringRef url) 114 { 115 persistentUserStyleSheetLocation = url; 116 } 117 118 bool setAlwaysAcceptCookies(bool alwaysAcceptCookies) 119 { 120 #if USE(CFNETWORK) 121 COMPtr<IWebCookieManager> cookieManager; 122 if (FAILED(WebKitCreateInstance(CLSID_WebCookieManager, 0, IID_IWebCookieManager, reinterpret_cast<void**>(&cookieManager)))) 123 return false; 124 CFHTTPCookieStorageRef cookieStorage = 0; 125 if (FAILED(cookieManager->cookieStorage(&cookieStorage)) || !cookieStorage) 126 return false; 127 128 WebKitCookieStorageAcceptPolicy cookieAcceptPolicy = alwaysAcceptCookies ? WebKitCookieStorageAcceptPolicyAlways : WebKitCookieStorageAcceptPolicyOnlyFromMainDocumentDomain; 129 CFHTTPCookieStorageSetCookieAcceptPolicy(cookieStorage, cookieAcceptPolicy); 130 return true; 131 #else 132 // FIXME: Implement! 133 return false; 134 #endif 135 } 136 137 wstring urlSuitableForTestResult(const wstring& url) 138 { 139 if (!url.c_str() || url.find(L"file://") == wstring::npos) 140 return url; 141 142 return PathFindFileNameW(url.c_str()); 143 } 144 145 static LRESULT CALLBACK DumpRenderTreeWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) 146 { 147 switch (msg) { 148 case WM_DESTROY: 149 for (unsigned i = openWindows().size() - 1; i >= 0; --i) { 150 if (openWindows()[i] == hWnd) { 151 openWindows().remove(i); 152 windowToWebViewMap().remove(hWnd); 153 break; 154 } 155 } 156 return 0; 157 break; 158 default: 159 return DefWindowProc(hWnd, msg, wParam, lParam); 160 } 161 } 162 163 static const wstring& exePath() 164 { 165 static wstring path; 166 static bool initialized; 167 168 if (initialized) 169 return path; 170 initialized = true; 171 172 TCHAR buffer[MAX_PATH]; 173 GetModuleFileName(GetModuleHandle(0), buffer, ARRAYSIZE(buffer)); 174 path = buffer; 175 int lastSlash = path.rfind('\\'); 176 if (lastSlash != -1 && lastSlash + 1 < path.length()) 177 path = path.substr(0, lastSlash + 1); 178 179 return path; 180 } 181 182 static const wstring& fontsPath() 183 { 184 static wstring path; 185 static bool initialized; 186 187 if (initialized) 188 return path; 189 initialized = true; 190 191 DWORD size = GetEnvironmentVariable(fontsEnvironmentVariable, 0, 0); 192 Vector<TCHAR> buffer(size); 193 if (GetEnvironmentVariable(fontsEnvironmentVariable, buffer.data(), buffer.size())) { 194 path = buffer.data(); 195 if (path[path.length() - 1] != '\\') 196 path.append(L"\\"); 197 return path; 198 } 199 200 path = exePath() + TEXT("DumpRenderTree.resources\\"); 201 return path; 202 } 203 204 static void addQTDirToPATH() 205 { 206 static LPCWSTR pathEnvironmentVariable = L"PATH"; 207 static LPCWSTR quickTimeKeyName = L"Software\\Apple Computer, Inc.\\QuickTime"; 208 static LPCWSTR quickTimeSysDir = L"QTSysDir"; 209 static bool initialized; 210 211 if (initialized) 212 return; 213 initialized = true; 214 215 // Get the QuickTime dll directory from the registry. The key can be in either HKLM or HKCU. 216 WCHAR qtPath[MAX_PATH]; 217 DWORD qtPathBufferLen = sizeof(qtPath); 218 DWORD keyType; 219 HRESULT result = SHGetValue(HKEY_LOCAL_MACHINE, quickTimeKeyName, quickTimeSysDir, &keyType, (LPVOID)qtPath, &qtPathBufferLen); 220 if (result != ERROR_SUCCESS || !qtPathBufferLen || keyType != REG_SZ) { 221 qtPathBufferLen = sizeof(qtPath); 222 result = SHGetValue(HKEY_CURRENT_USER, quickTimeKeyName, quickTimeSysDir, &keyType, (LPVOID)qtPath, &qtPathBufferLen); 223 if (result != ERROR_SUCCESS || !qtPathBufferLen || keyType != REG_SZ) 224 return; 225 } 226 227 // Read the current PATH. 228 DWORD pathSize = GetEnvironmentVariableW(pathEnvironmentVariable, 0, 0); 229 Vector<WCHAR> oldPath(pathSize); 230 if (!GetEnvironmentVariableW(pathEnvironmentVariable, oldPath.data(), oldPath.size())) 231 return; 232 233 // And add the QuickTime dll. 234 wstring newPath; 235 newPath.append(qtPath); 236 newPath.append(L";"); 237 newPath.append(oldPath.data(), oldPath.size()); 238 SetEnvironmentVariableW(pathEnvironmentVariable, newPath.data()); 239 } 240 241 #ifdef DEBUG_ALL 242 #define WEBKITDLL TEXT("WebKit_debug.dll") 243 #else 244 #define WEBKITDLL TEXT("WebKit.dll") 245 #endif 246 247 static void initialize() 248 { 249 if (HMODULE webKitModule = LoadLibrary(WEBKITDLL)) 250 if (FARPROC dllRegisterServer = GetProcAddress(webKitModule, "DllRegisterServer")) 251 dllRegisterServer(); 252 253 // Init COM 254 OleInitialize(0); 255 256 static LPCTSTR fontsToInstall[] = { 257 TEXT("AHEM____.ttf"), 258 TEXT("Apple Chancery.ttf"), 259 TEXT("Courier Bold.ttf"), 260 TEXT("Courier.ttf"), 261 TEXT("Helvetica Bold Oblique.ttf"), 262 TEXT("Helvetica Bold.ttf"), 263 TEXT("Helvetica Oblique.ttf"), 264 TEXT("Helvetica.ttf"), 265 TEXT("Helvetica Neue Bold Italic.ttf"), 266 TEXT("Helvetica Neue Bold.ttf"), 267 TEXT("Helvetica Neue Condensed Black.ttf"), 268 TEXT("Helvetica Neue Condensed Bold.ttf"), 269 TEXT("Helvetica Neue Italic.ttf"), 270 TEXT("Helvetica Neue Light Italic.ttf"), 271 TEXT("Helvetica Neue Light.ttf"), 272 TEXT("Helvetica Neue UltraLight Italic.ttf"), 273 TEXT("Helvetica Neue UltraLight.ttf"), 274 TEXT("Helvetica Neue.ttf"), 275 TEXT("Lucida Grande.ttf"), 276 TEXT("Lucida Grande Bold.ttf"), 277 TEXT("Monaco.ttf"), 278 TEXT("Papyrus.ttf"), 279 TEXT("Times Bold Italic.ttf"), 280 TEXT("Times Bold.ttf"), 281 TEXT("Times Italic.ttf"), 282 TEXT("Times Roman.ttf"), 283 TEXT("WebKit Layout Tests 2.ttf"), 284 TEXT("WebKit Layout Tests.ttf"), 285 TEXT("WebKitWeightWatcher100.ttf"), 286 TEXT("WebKitWeightWatcher200.ttf"), 287 TEXT("WebKitWeightWatcher300.ttf"), 288 TEXT("WebKitWeightWatcher400.ttf"), 289 TEXT("WebKitWeightWatcher500.ttf"), 290 TEXT("WebKitWeightWatcher600.ttf"), 291 TEXT("WebKitWeightWatcher700.ttf"), 292 TEXT("WebKitWeightWatcher800.ttf"), 293 TEXT("WebKitWeightWatcher900.ttf") 294 }; 295 296 wstring resourcesPath = fontsPath(); 297 298 COMPtr<IWebTextRenderer> textRenderer; 299 if (SUCCEEDED(WebKitCreateInstance(CLSID_WebTextRenderer, 0, IID_IWebTextRenderer, (void**)&textRenderer))) 300 for (int i = 0; i < ARRAYSIZE(fontsToInstall); ++i) 301 textRenderer->registerPrivateFont(wstring(resourcesPath + fontsToInstall[i]).c_str()); 302 303 // Add the QuickTime dll directory to PATH or QT 7.6 will fail to initialize on systems 304 // linked with older versions of qtmlclientlib.dll. 305 addQTDirToPATH(); 306 307 // Register a host window 308 WNDCLASSEX wcex; 309 310 wcex.cbSize = sizeof(WNDCLASSEX); 311 312 wcex.style = CS_HREDRAW | CS_VREDRAW; 313 wcex.lpfnWndProc = DumpRenderTreeWndProc; 314 wcex.cbClsExtra = 0; 315 wcex.cbWndExtra = 0; 316 wcex.hInstance = GetModuleHandle(0); 317 wcex.hIcon = 0; 318 wcex.hCursor = LoadCursor(0, IDC_ARROW); 319 wcex.hbrBackground = 0; 320 wcex.lpszMenuName = 0; 321 wcex.lpszClassName = kDumpRenderTreeClassName; 322 wcex.hIconSm = 0; 323 324 RegisterClassEx(&wcex); 325 } 326 327 void displayWebView() 328 { 329 ::InvalidateRect(webViewWindow, 0, TRUE); 330 ::SendMessage(webViewWindow, WM_PAINT, 0, 0); 331 } 332 333 void dumpFrameScrollPosition(IWebFrame* frame) 334 { 335 if (!frame) 336 return; 337 338 COMPtr<IWebFramePrivate> framePrivate; 339 if (FAILED(frame->QueryInterface(&framePrivate))) 340 return; 341 342 SIZE scrollPosition; 343 if (FAILED(framePrivate->scrollOffset(&scrollPosition))) 344 return; 345 346 if (abs(scrollPosition.cx) > 0.00000001 || abs(scrollPosition.cy) > 0.00000001) { 347 COMPtr<IWebFrame> parent; 348 if (FAILED(frame->parentFrame(&parent))) 349 return; 350 if (parent) { 351 BSTR name; 352 if (FAILED(frame->name(&name))) 353 return; 354 printf("frame '%S' ", name ? name : L""); 355 SysFreeString(name); 356 } 357 printf("scrolled to %.f,%.f\n", (double)scrollPosition.cx, (double)scrollPosition.cy); 358 } 359 360 if (::gLayoutTestController->dumpChildFrameScrollPositions()) { 361 COMPtr<IEnumVARIANT> enumKids; 362 if (FAILED(frame->childFrames(&enumKids))) 363 return; 364 VARIANT var; 365 VariantInit(&var); 366 while (enumKids->Next(1, &var, 0) == S_OK) { 367 ASSERT(V_VT(&var) == VT_UNKNOWN); 368 COMPtr<IWebFrame> framePtr; 369 V_UNKNOWN(&var)->QueryInterface(IID_IWebFrame, (void**)&framePtr); 370 dumpFrameScrollPosition(framePtr.get()); 371 VariantClear(&var); 372 } 373 } 374 } 375 376 static wstring dumpFramesAsText(IWebFrame* frame) 377 { 378 if (!frame) 379 return L""; 380 381 COMPtr<IDOMDocument> document; 382 if (FAILED(frame->DOMDocument(&document))) 383 return L""; 384 385 COMPtr<IDOMElement> documentElement; 386 if (FAILED(document->documentElement(&documentElement))) 387 return L""; 388 389 wstring result; 390 391 // Add header for all but the main frame. 392 COMPtr<IWebFrame> parent; 393 if (FAILED(frame->parentFrame(&parent))) 394 return L""; 395 if (parent) { 396 BSTR name = L""; 397 if (FAILED(frame->name(&name))) 398 return L""; 399 400 result.append(L"\n--------\nFrame: '"); 401 result.append(name ? name : L"", SysStringLen(name)); 402 result.append(L"'\n--------\n"); 403 404 SysFreeString(name); 405 } 406 407 BSTR innerText = 0; 408 COMPtr<IDOMElementPrivate> docPrivate; 409 if (SUCCEEDED(documentElement->QueryInterface(&docPrivate))) 410 docPrivate->innerText(&innerText); 411 412 result.append(innerText ? innerText : L"", SysStringLen(innerText)); 413 result.append(L"\n"); 414 415 SysFreeString(innerText); 416 417 if (::gLayoutTestController->dumpChildFramesAsText()) { 418 COMPtr<IEnumVARIANT> enumKids; 419 if (FAILED(frame->childFrames(&enumKids))) 420 return L""; 421 VARIANT var; 422 VariantInit(&var); 423 while (enumKids->Next(1, &var, 0) == S_OK) { 424 ASSERT(V_VT(&var) == VT_UNKNOWN); 425 COMPtr<IWebFrame> framePtr; 426 V_UNKNOWN(&var)->QueryInterface(IID_IWebFrame, (void**)&framePtr); 427 result.append(dumpFramesAsText(framePtr.get())); 428 VariantClear(&var); 429 } 430 } 431 432 return result; 433 } 434 435 static int compareHistoryItems(const void* item1, const void* item2) 436 { 437 COMPtr<IWebHistoryItemPrivate> itemA; 438 if (FAILED((*(COMPtr<IUnknown>*)item1)->QueryInterface(&itemA))) 439 return 0; 440 441 COMPtr<IWebHistoryItemPrivate> itemB; 442 if (FAILED((*(COMPtr<IUnknown>*)item2)->QueryInterface(&itemB))) 443 return 0; 444 445 BSTR targetA; 446 if (FAILED(itemA->target(&targetA))) 447 return 0; 448 449 BSTR targetB; 450 if (FAILED(itemB->target(&targetB))) { 451 SysFreeString(targetA); 452 return 0; 453 } 454 455 int result = wcsicmp(wstring(targetA, SysStringLen(targetA)).c_str(), wstring(targetB, SysStringLen(targetB)).c_str()); 456 SysFreeString(targetA); 457 SysFreeString(targetB); 458 return result; 459 } 460 461 static void dumpHistoryItem(IWebHistoryItem* item, int indent, bool current) 462 { 463 assert(item); 464 465 int start = 0; 466 if (current) { 467 printf("curr->"); 468 start = 6; 469 } 470 for (int i = start; i < indent; i++) 471 putchar(' '); 472 473 BSTR url; 474 if (FAILED(item->URLString(&url))) 475 return; 476 477 if (wcsstr(url, L"file:/") == url) { 478 static wchar_t* layoutTestsString = L"/LayoutTests/"; 479 static wchar_t* fileTestString = L"(file test):"; 480 481 wchar_t* result = wcsstr(url, layoutTestsString); 482 if (result == NULL) 483 return; 484 wchar_t* start = result + wcslen(layoutTestsString); 485 486 BSTR newURL = SysAllocStringLen(NULL, SysStringLen(url)); 487 wcscpy(newURL, fileTestString); 488 wcscpy(newURL + wcslen(fileTestString), start); 489 490 SysFreeString(url); 491 url = newURL; 492 } 493 494 printf("%S", url ? url : L""); 495 SysFreeString(url); 496 497 COMPtr<IWebHistoryItemPrivate> itemPrivate; 498 if (FAILED(item->QueryInterface(&itemPrivate))) 499 return; 500 501 BSTR target; 502 if (FAILED(itemPrivate->target(&target))) 503 return; 504 if (SysStringLen(target)) 505 printf(" (in frame \"%S\")", target); 506 SysFreeString(target); 507 BOOL isTargetItem = FALSE; 508 if (FAILED(itemPrivate->isTargetItem(&isTargetItem))) 509 return; 510 if (isTargetItem) 511 printf(" **nav target**"); 512 putchar('\n'); 513 514 unsigned kidsCount; 515 SAFEARRAY* arrPtr; 516 if (FAILED(itemPrivate->children(&kidsCount, &arrPtr)) || !kidsCount) 517 return; 518 519 Vector<COMPtr<IUnknown> > kidsVector; 520 521 LONG lowerBound; 522 if (FAILED(::SafeArrayGetLBound(arrPtr, 1, &lowerBound))) 523 goto exit; 524 525 LONG upperBound; 526 if (FAILED(::SafeArrayGetUBound(arrPtr, 1, &upperBound))) 527 goto exit; 528 529 LONG length = upperBound - lowerBound + 1; 530 if (!length) 531 goto exit; 532 ASSERT(length == kidsCount); 533 534 IUnknown** safeArrayData; 535 if (FAILED(::SafeArrayAccessData(arrPtr, (void**)&safeArrayData))) 536 goto exit; 537 538 for (int i = 0; i < length; ++i) 539 kidsVector.append(safeArrayData[i]); 540 ::SafeArrayUnaccessData(arrPtr); 541 542 // must sort to eliminate arbitrary result ordering which defeats reproducible testing 543 qsort(kidsVector.data(), kidsCount, sizeof(kidsVector[0]), compareHistoryItems); 544 545 for (unsigned i = 0; i < kidsCount; ++i) { 546 COMPtr<IWebHistoryItem> item; 547 kidsVector[i]->QueryInterface(&item); 548 dumpHistoryItem(item.get(), indent + 4, false); 549 } 550 551 exit: 552 if (arrPtr && SUCCEEDED(::SafeArrayUnlock(arrPtr))) 553 ::SafeArrayDestroy(arrPtr); 554 } 555 556 static void dumpBackForwardList(IWebView* webView) 557 { 558 ASSERT(webView); 559 560 printf("\n============== Back Forward List ==============\n"); 561 562 COMPtr<IWebBackForwardList> bfList; 563 if (FAILED(webView->backForwardList(&bfList))) 564 return; 565 566 // Print out all items in the list after prevTestBFItem, which was from the previous test 567 // Gather items from the end of the list, the print them out from oldest to newest 568 569 Vector<COMPtr<IUnknown> > itemsToPrint; 570 571 int forwardListCount; 572 if (FAILED(bfList->forwardListCount(&forwardListCount))) 573 return; 574 575 for (int i = forwardListCount; i > 0; --i) { 576 COMPtr<IWebHistoryItem> item; 577 if (FAILED(bfList->itemAtIndex(i, &item))) 578 return; 579 // something is wrong if the item from the last test is in the forward part of the b/f list 580 assert(item != prevTestBFItem); 581 COMPtr<IUnknown> itemUnknown; 582 item->QueryInterface(&itemUnknown); 583 itemsToPrint.append(itemUnknown); 584 } 585 586 COMPtr<IWebHistoryItem> currentItem; 587 if (FAILED(bfList->currentItem(¤tItem))) 588 return; 589 590 assert(currentItem != prevTestBFItem); 591 COMPtr<IUnknown> currentItemUnknown; 592 currentItem->QueryInterface(¤tItemUnknown); 593 itemsToPrint.append(currentItemUnknown); 594 int currentItemIndex = itemsToPrint.size() - 1; 595 596 int backListCount; 597 if (FAILED(bfList->backListCount(&backListCount))) 598 return; 599 600 for (int i = -1; i >= -backListCount; --i) { 601 COMPtr<IWebHistoryItem> item; 602 if (FAILED(bfList->itemAtIndex(i, &item))) 603 return; 604 if (item == prevTestBFItem) 605 break; 606 COMPtr<IUnknown> itemUnknown; 607 item->QueryInterface(&itemUnknown); 608 itemsToPrint.append(itemUnknown); 609 } 610 611 for (int i = itemsToPrint.size() - 1; i >= 0; --i) { 612 COMPtr<IWebHistoryItem> historyItemToPrint; 613 itemsToPrint[i]->QueryInterface(&historyItemToPrint); 614 dumpHistoryItem(historyItemToPrint.get(), 8, i == currentItemIndex); 615 } 616 617 printf("===============================================\n"); 618 } 619 620 static void dumpBackForwardListForAllWindows() 621 { 622 unsigned count = openWindows().size(); 623 for (unsigned i = 0; i < count; i++) { 624 HWND window = openWindows()[i]; 625 IWebView* webView = windowToWebViewMap().get(window).get(); 626 dumpBackForwardList(webView); 627 } 628 } 629 630 static void invalidateAnyPreviousWaitToDumpWatchdog() 631 { 632 if (!waitToDumpWatchdog) 633 return; 634 635 KillTimer(0, waitToDumpWatchdog); 636 waitToDumpWatchdog = 0; 637 } 638 639 void dump() 640 { 641 invalidateAnyPreviousWaitToDumpWatchdog(); 642 643 COMPtr<IWebDataSource> dataSource; 644 if (SUCCEEDED(frame->dataSource(&dataSource))) { 645 COMPtr<IWebURLResponse> response; 646 if (SUCCEEDED(dataSource->response(&response)) && response) { 647 BSTR mimeType; 648 if (SUCCEEDED(response->MIMEType(&mimeType))) 649 ::gLayoutTestController->setDumpAsText(::gLayoutTestController->dumpAsText() | !_tcscmp(mimeType, TEXT("text/plain"))); 650 SysFreeString(mimeType); 651 } 652 } 653 654 BSTR resultString = 0; 655 656 if (dumpTree) { 657 if (::gLayoutTestController->dumpAsText()) { 658 ::InvalidateRect(webViewWindow, 0, TRUE); 659 ::SendMessage(webViewWindow, WM_PAINT, 0, 0); 660 wstring result = dumpFramesAsText(frame); 661 resultString = SysAllocStringLen(result.data(), result.size()); 662 } else { 663 bool isSVGW3CTest = (gLayoutTestController->testPathOrURL().find("svg\\W3C-SVG-1.1") != string::npos); 664 unsigned width; 665 unsigned height; 666 if (isSVGW3CTest) { 667 width = 480; 668 height = 360; 669 } else { 670 width = maxViewWidth; 671 height = maxViewHeight; 672 } 673 674 ::SetWindowPos(webViewWindow, 0, 0, 0, width, height, SWP_NOMOVE); 675 ::InvalidateRect(webViewWindow, 0, TRUE); 676 ::SendMessage(webViewWindow, WM_PAINT, 0, 0); 677 678 COMPtr<IWebFramePrivate> framePrivate; 679 if (FAILED(frame->QueryInterface(&framePrivate))) 680 goto fail; 681 framePrivate->renderTreeAsExternalRepresentation(&resultString); 682 } 683 684 if (!resultString) 685 printf("ERROR: nil result from %s", ::gLayoutTestController->dumpAsText() ? "IDOMElement::innerText" : "IFrameViewPrivate::renderTreeAsExternalRepresentation"); 686 else { 687 unsigned stringLength = SysStringLen(resultString); 688 int bufferSize = ::WideCharToMultiByte(CP_UTF8, 0, resultString, stringLength, 0, 0, 0, 0); 689 char* buffer = (char*)malloc(bufferSize + 1); 690 ::WideCharToMultiByte(CP_UTF8, 0, resultString, stringLength, buffer, bufferSize + 1, 0, 0); 691 fwrite(buffer, 1, bufferSize, stdout); 692 free(buffer); 693 if (!::gLayoutTestController->dumpAsText()) 694 dumpFrameScrollPosition(frame); 695 } 696 if (::gLayoutTestController->dumpBackForwardList()) 697 dumpBackForwardListForAllWindows(); 698 } 699 700 if (printSeparators) { 701 puts("#EOF"); // terminate the content block 702 fputs("#EOF\n", stderr); 703 fflush(stdout); 704 fflush(stderr); 705 } 706 707 if (dumpPixels) { 708 if (!gLayoutTestController->dumpAsText() && !gLayoutTestController->dumpDOMAsWebArchive() && !gLayoutTestController->dumpSourceAsWebArchive()) 709 dumpWebViewAsPixelsAndCompareWithExpected(gLayoutTestController->expectedPixelHash()); 710 } 711 712 printf("#EOF\n"); // terminate the (possibly empty) pixels block 713 fflush(stdout); 714 715 fail: 716 SysFreeString(resultString); 717 // This will exit from our message loop. 718 PostQuitMessage(0); 719 done = true; 720 } 721 722 static bool shouldLogFrameLoadDelegates(const char* pathOrURL) 723 { 724 return strstr(pathOrURL, "/loading/") || strstr(pathOrURL, "\\loading\\"); 725 } 726 727 static bool shouldLogHistoryDelegates(const char* pathOrURL) 728 { 729 return strstr(pathOrURL, "/globalhistory/") || strstr(pathOrURL, "\\globalhistory\\"); 730 } 731 732 static bool shouldOpenWebInspector(const char* pathOrURL) 733 { 734 return strstr(pathOrURL, "/inspector/") || strstr(pathOrURL, "\\inspector\\"); 735 } 736 737 static void resetDefaultsToConsistentValues(IWebPreferences* preferences) 738 { 739 #ifdef USE_MAC_FONTS 740 static BSTR standardFamily = SysAllocString(TEXT("Times")); 741 static BSTR fixedFamily = SysAllocString(TEXT("Courier")); 742 static BSTR sansSerifFamily = SysAllocString(TEXT("Helvetica")); 743 static BSTR cursiveFamily = SysAllocString(TEXT("Apple Chancery")); 744 static BSTR fantasyFamily = SysAllocString(TEXT("Papyrus")); 745 #else 746 static BSTR standardFamily = SysAllocString(TEXT("Times New Roman")); 747 static BSTR fixedFamily = SysAllocString(TEXT("Courier New")); 748 static BSTR sansSerifFamily = SysAllocString(TEXT("Arial")); 749 static BSTR cursiveFamily = SysAllocString(TEXT("Comic Sans MS")); // Not actually cursive, but it's what IE and Firefox use. 750 static BSTR fantasyFamily = SysAllocString(TEXT("Times New Roman")); 751 #endif 752 753 preferences->setStandardFontFamily(standardFamily); 754 preferences->setFixedFontFamily(fixedFamily); 755 preferences->setSerifFontFamily(standardFamily); 756 preferences->setSansSerifFontFamily(sansSerifFamily); 757 preferences->setCursiveFontFamily(cursiveFamily); 758 preferences->setFantasyFontFamily(fantasyFamily); 759 760 preferences->setAutosaves(FALSE); 761 preferences->setDefaultFontSize(16); 762 preferences->setDefaultFixedFontSize(13); 763 preferences->setMinimumFontSize(1); 764 preferences->setJavaEnabled(FALSE); 765 preferences->setPlugInsEnabled(TRUE); 766 preferences->setDOMPasteAllowed(TRUE); 767 preferences->setEditableLinkBehavior(WebKitEditableLinkOnlyLiveWithShiftKey); 768 preferences->setFontSmoothing(FontSmoothingTypeStandard); 769 preferences->setUsesPageCache(FALSE); 770 preferences->setPrivateBrowsingEnabled(FALSE); 771 preferences->setJavaScriptCanOpenWindowsAutomatically(TRUE); 772 preferences->setJavaScriptEnabled(TRUE); 773 preferences->setTabsToLinks(FALSE); 774 preferences->setShouldPrintBackgrounds(TRUE); 775 preferences->setLoadsImagesAutomatically(TRUE); 776 777 if (persistentUserStyleSheetLocation) { 778 Vector<wchar_t> urlCharacters(CFStringGetLength(persistentUserStyleSheetLocation.get())); 779 CFStringGetCharacters(persistentUserStyleSheetLocation.get(), CFRangeMake(0, CFStringGetLength(persistentUserStyleSheetLocation.get())), (UniChar *)urlCharacters.data()); 780 BSTR url = SysAllocStringLen(urlCharacters.data(), urlCharacters.size()); 781 preferences->setUserStyleSheetLocation(url); 782 SysFreeString(url); 783 preferences->setUserStyleSheetEnabled(TRUE); 784 } else 785 preferences->setUserStyleSheetEnabled(FALSE); 786 787 COMPtr<IWebPreferencesPrivate> prefsPrivate(Query, preferences); 788 if (prefsPrivate) { 789 prefsPrivate->setAllowUniversalAccessFromFileURLs(TRUE); 790 prefsPrivate->setAuthorAndUserStylesEnabled(TRUE); 791 prefsPrivate->setDeveloperExtrasEnabled(FALSE); 792 prefsPrivate->setExperimentalNotificationsEnabled(TRUE); 793 prefsPrivate->setShouldPaintNativeControls(FALSE); // FIXME - need to make DRT pass with Windows native controls <http://bugs.webkit.org/show_bug.cgi?id=25592> 794 prefsPrivate->setXSSAuditorEnabled(FALSE); 795 prefsPrivate->setFrameSetFlatteningEnabled(FALSE); 796 prefsPrivate->setOfflineWebApplicationCacheEnabled(TRUE); 797 } 798 setAlwaysAcceptCookies(false); 799 800 setlocale(LC_ALL, ""); 801 } 802 803 static void resetWebViewToConsistentStateBeforeTesting() 804 { 805 COMPtr<IWebView> webView; 806 if (FAILED(frame->webView(&webView))) 807 return; 808 809 webView->setPolicyDelegate(0); 810 policyDelegate->setPermissive(false); 811 policyDelegate->setControllerToNotifyDone(0); 812 813 COMPtr<IWebIBActions> webIBActions(Query, webView); 814 if (webIBActions) { 815 webIBActions->makeTextStandardSize(0); 816 webIBActions->resetPageZoom(0); 817 } 818 819 820 COMPtr<IWebPreferences> preferences; 821 if (SUCCEEDED(webView->preferences(&preferences))) 822 resetDefaultsToConsistentValues(preferences.get()); 823 824 COMPtr<IWebViewEditing> viewEditing; 825 if (SUCCEEDED(webView->QueryInterface(&viewEditing))) 826 viewEditing->setSmartInsertDeleteEnabled(TRUE); 827 828 COMPtr<IWebViewPrivate> webViewPrivate(Query, webView); 829 if (!webViewPrivate) 830 return; 831 832 COMPtr<IWebInspector> inspector; 833 if (SUCCEEDED(webViewPrivate->inspector(&inspector))) 834 inspector->setJavaScriptProfilingEnabled(FALSE); 835 836 HWND viewWindow; 837 if (SUCCEEDED(webViewPrivate->viewWindow(reinterpret_cast<OLE_HANDLE*>(&viewWindow))) && viewWindow) 838 SetFocus(viewWindow); 839 840 webViewPrivate->clearMainFrameName(); 841 webViewPrivate->resetOriginAccessWhiteLists(); 842 843 BSTR groupName; 844 if (SUCCEEDED(webView->groupName(&groupName))) { 845 webViewPrivate->removeAllUserContentFromGroup(groupName); 846 SysFreeString(groupName); 847 } 848 849 sharedUIDelegate->resetUndoManager(); 850 851 sharedFrameLoadDelegate->resetToConsistentState(); 852 } 853 854 static void runTest(const string& testPathOrURL) 855 { 856 static BSTR methodBStr = SysAllocString(TEXT("GET")); 857 858 // Look for "'" as a separator between the path or URL, and the pixel dump hash that follows. 859 string pathOrURL(testPathOrURL); 860 string expectedPixelHash; 861 862 size_t separatorPos = pathOrURL.find("'"); 863 if (separatorPos != string::npos) { 864 pathOrURL = string(testPathOrURL, 0, separatorPos); 865 expectedPixelHash = string(testPathOrURL, separatorPos + 1); 866 } 867 868 BSTR urlBStr; 869 870 CFStringRef str = CFStringCreateWithCString(0, pathOrURL.c_str(), kCFStringEncodingWindowsLatin1); 871 CFURLRef url = CFURLCreateWithString(0, str, 0); 872 873 if (!url) 874 url = CFURLCreateWithFileSystemPath(0, str, kCFURLWindowsPathStyle, false); 875 876 CFRelease(str); 877 878 str = CFURLGetString(url); 879 880 CFIndex length = CFStringGetLength(str); 881 UniChar* buffer = new UniChar[length]; 882 883 CFStringGetCharacters(str, CFRangeMake(0, length), buffer); 884 urlBStr = SysAllocStringLen((OLECHAR*)buffer, length); 885 delete[] buffer; 886 887 CFRelease(url); 888 889 ::gLayoutTestController = new LayoutTestController(pathOrURL, expectedPixelHash); 890 done = false; 891 topLoadingFrame = 0; 892 893 gLayoutTestController->setIconDatabaseEnabled(false); 894 895 if (shouldLogFrameLoadDelegates(pathOrURL.c_str())) 896 gLayoutTestController->setDumpFrameLoadCallbacks(true); 897 898 COMPtr<IWebView> webView; 899 if (SUCCEEDED(frame->webView(&webView))) { 900 COMPtr<IWebViewPrivate> viewPrivate; 901 if (SUCCEEDED(webView->QueryInterface(&viewPrivate))) { 902 if (shouldLogHistoryDelegates(pathOrURL.c_str())) { 903 gLayoutTestController->setDumpHistoryDelegateCallbacks(true); 904 viewPrivate->setHistoryDelegate(sharedHistoryDelegate.get()); 905 } else 906 viewPrivate->setHistoryDelegate(0); 907 } 908 } 909 COMPtr<IWebHistory> history; 910 if (SUCCEEDED(WebKitCreateInstance(CLSID_WebHistory, 0, __uuidof(history), reinterpret_cast<void**>(&history)))) 911 history->setOptionalSharedHistory(0); 912 913 resetWebViewToConsistentStateBeforeTesting(); 914 915 if (shouldOpenWebInspector(pathOrURL.c_str())) 916 gLayoutTestController->showWebInspector(); 917 918 prevTestBFItem = 0; 919 if (webView) { 920 COMPtr<IWebBackForwardList> bfList; 921 if (SUCCEEDED(webView->backForwardList(&bfList))) 922 bfList->currentItem(&prevTestBFItem); 923 } 924 925 WorkQueue::shared()->clear(); 926 WorkQueue::shared()->setFrozen(false); 927 928 HWND hostWindow; 929 webView->hostWindow(reinterpret_cast<OLE_HANDLE*>(&hostWindow)); 930 931 COMPtr<IWebMutableURLRequest> request; 932 HRESULT hr = WebKitCreateInstance(CLSID_WebMutableURLRequest, 0, IID_IWebMutableURLRequest, (void**)&request); 933 if (FAILED(hr)) 934 goto exit; 935 936 request->initWithURL(urlBStr, WebURLRequestUseProtocolCachePolicy, 60); 937 938 request->setHTTPMethod(methodBStr); 939 frame->loadRequest(request.get()); 940 941 MSG msg; 942 while (GetMessage(&msg, 0, 0, 0)) { 943 // We get spurious WM_MOUSELEAVE events which make event handling machinery think that mouse button 944 // is released during dragging (see e.g. fast\dynamic\layer-hit-test-crash.html). 945 // Mouse can never leave WebView during normal DumpRenderTree operation, so we just ignore all such events. 946 if (msg.message == WM_MOUSELEAVE) 947 continue; 948 TranslateMessage(&msg); 949 DispatchMessage(&msg); 950 } 951 952 if (shouldOpenWebInspector(pathOrURL.c_str())) 953 gLayoutTestController->closeWebInspector(); 954 955 resetWebViewToConsistentStateBeforeTesting(); 956 957 frame->stopLoading(); 958 959 if (::gLayoutTestController->closeRemainingWindowsWhenComplete()) { 960 Vector<HWND> windows = openWindows(); 961 unsigned size = windows.size(); 962 for (unsigned i = 0; i < size; i++) { 963 HWND window = windows[i]; 964 965 // Don't try to close the main window 966 if (window == hostWindow) 967 continue; 968 969 DestroyWindow(window); 970 } 971 } 972 973 exit: 974 SysFreeString(urlBStr); 975 ::gLayoutTestController->deref(); 976 ::gLayoutTestController = 0; 977 978 return; 979 } 980 981 static Boolean pthreadEqualCallback(const void* value1, const void* value2) 982 { 983 return (Boolean)pthread_equal(*(pthread_t*)value1, *(pthread_t*)value2); 984 } 985 986 static CFDictionaryKeyCallBacks pthreadKeyCallbacks = { 0, 0, 0, 0, pthreadEqualCallback, 0 }; 987 988 static pthread_mutex_t javaScriptThreadsMutex = PTHREAD_MUTEX_INITIALIZER; 989 static bool javaScriptThreadsShouldTerminate; 990 991 static const int javaScriptThreadsCount = 4; 992 static CFMutableDictionaryRef javaScriptThreads() 993 { 994 assert(pthread_mutex_trylock(&javaScriptThreadsMutex) == EBUSY); 995 static CFMutableDictionaryRef staticJavaScriptThreads; 996 if (!staticJavaScriptThreads) 997 staticJavaScriptThreads = CFDictionaryCreateMutable(0, 0, &pthreadKeyCallbacks, 0); 998 return staticJavaScriptThreads; 999 } 1000 1001 // Loops forever, running a script and randomly respawning, until 1002 // javaScriptThreadsShouldTerminate becomes true. 1003 void* runJavaScriptThread(void* arg) 1004 { 1005 const char* const script = 1006 " \ 1007 var array = []; \ 1008 for (var i = 0; i < 10; i++) { \ 1009 array.push(String(i)); \ 1010 } \ 1011 "; 1012 1013 while (true) { 1014 JSGlobalContextRef ctx = JSGlobalContextCreate(0); 1015 JSStringRef scriptRef = JSStringCreateWithUTF8CString(script); 1016 1017 JSValueRef exception = 0; 1018 JSEvaluateScript(ctx, scriptRef, 0, 0, 1, &exception); 1019 assert(!exception); 1020 1021 JSGlobalContextRelease(ctx); 1022 JSStringRelease(scriptRef); 1023 1024 JSGarbageCollect(ctx); 1025 1026 pthread_mutex_lock(&javaScriptThreadsMutex); 1027 1028 // Check for cancellation. 1029 if (javaScriptThreadsShouldTerminate) { 1030 pthread_mutex_unlock(&javaScriptThreadsMutex); 1031 return 0; 1032 } 1033 1034 // Respawn probabilistically. 1035 if (rand() % 5 == 0) { 1036 pthread_t pthread; 1037 pthread_create(&pthread, 0, &runJavaScriptThread, 0); 1038 pthread_detach(pthread); 1039 1040 pthread_t self = pthread_self(); 1041 CFDictionaryRemoveValue(javaScriptThreads(), self.p); 1042 CFDictionaryAddValue(javaScriptThreads(), pthread.p, 0); 1043 1044 pthread_mutex_unlock(&javaScriptThreadsMutex); 1045 return 0; 1046 } 1047 1048 pthread_mutex_unlock(&javaScriptThreadsMutex); 1049 } 1050 } 1051 1052 static void startJavaScriptThreads(void) 1053 { 1054 pthread_mutex_lock(&javaScriptThreadsMutex); 1055 1056 for (int i = 0; i < javaScriptThreadsCount; i++) { 1057 pthread_t pthread; 1058 pthread_create(&pthread, 0, &runJavaScriptThread, 0); 1059 pthread_detach(pthread); 1060 CFDictionaryAddValue(javaScriptThreads(), pthread.p, 0); 1061 } 1062 1063 pthread_mutex_unlock(&javaScriptThreadsMutex); 1064 } 1065 1066 static void stopJavaScriptThreads(void) 1067 { 1068 pthread_mutex_lock(&javaScriptThreadsMutex); 1069 1070 javaScriptThreadsShouldTerminate = true; 1071 1072 pthread_t* pthreads[javaScriptThreadsCount] = {0}; 1073 int threadDictCount = CFDictionaryGetCount(javaScriptThreads()); 1074 assert(threadDictCount == javaScriptThreadsCount); 1075 CFDictionaryGetKeysAndValues(javaScriptThreads(), (const void**)pthreads, 0); 1076 1077 pthread_mutex_unlock(&javaScriptThreadsMutex); 1078 1079 for (int i = 0; i < javaScriptThreadsCount; i++) { 1080 pthread_t* pthread = pthreads[i]; 1081 pthread_join(*pthread, 0); 1082 free(pthread); 1083 } 1084 } 1085 1086 Vector<HWND>& openWindows() 1087 { 1088 static Vector<HWND> vector; 1089 return vector; 1090 } 1091 1092 WindowToWebViewMap& windowToWebViewMap() 1093 { 1094 static WindowToWebViewMap map; 1095 return map; 1096 } 1097 1098 IWebView* createWebViewAndOffscreenWindow(HWND* webViewWindow) 1099 { 1100 HWND hostWindow = CreateWindowEx(WS_EX_TOOLWINDOW, kDumpRenderTreeClassName, TEXT("DumpRenderTree"), WS_POPUP, 1101 -maxViewWidth, -maxViewHeight, maxViewWidth, maxViewHeight, 0, 0, GetModuleHandle(0), 0); 1102 1103 IWebView* webView; 1104 1105 HRESULT hr = WebKitCreateInstance(CLSID_WebView, 0, IID_IWebView, (void**)&webView); 1106 if (FAILED(hr)) { 1107 fprintf(stderr, "Failed to create CLSID_WebView instance, error 0x%x\n", hr); 1108 return 0; 1109 } 1110 1111 if (FAILED(webView->setHostWindow((OLE_HANDLE)(ULONG64)hostWindow))) 1112 return 0; 1113 1114 RECT clientRect; 1115 clientRect.bottom = clientRect.left = clientRect.top = clientRect.right = 0; 1116 BSTR groupName = SysAllocString(L"org.webkit.DumpRenderTree"); 1117 bool failed = FAILED(webView->initWithFrame(clientRect, 0, groupName)); 1118 SysFreeString(groupName); 1119 if (failed) 1120 return 0; 1121 1122 COMPtr<IWebViewPrivate> viewPrivate; 1123 if (FAILED(webView->QueryInterface(&viewPrivate))) 1124 return 0; 1125 1126 viewPrivate->setShouldApplyMacFontAscentHack(TRUE); 1127 viewPrivate->setAlwaysUsesComplexTextCodePath(forceComplexText); 1128 1129 BSTR pluginPath = SysAllocStringLen(0, exePath().length() + _tcslen(TestPluginDir)); 1130 _tcscpy(pluginPath, exePath().c_str()); 1131 _tcscat(pluginPath, TestPluginDir); 1132 failed = FAILED(viewPrivate->addAdditionalPluginDirectory(pluginPath)); 1133 SysFreeString(pluginPath); 1134 if (failed) 1135 return 0; 1136 1137 HWND viewWindow; 1138 if (FAILED(viewPrivate->viewWindow(reinterpret_cast<OLE_HANDLE*>(&viewWindow)))) 1139 return 0; 1140 if (webViewWindow) 1141 *webViewWindow = viewWindow; 1142 1143 SetWindowPos(viewWindow, 0, 0, 0, maxViewWidth, maxViewHeight, 0); 1144 ShowWindow(hostWindow, SW_SHOW); 1145 1146 if (FAILED(webView->setFrameLoadDelegate(sharedFrameLoadDelegate.get()))) 1147 return 0; 1148 1149 if (FAILED(viewPrivate->setFrameLoadDelegatePrivate(sharedFrameLoadDelegate.get()))) 1150 return 0; 1151 1152 if (FAILED(webView->setUIDelegate(sharedUIDelegate.get()))) 1153 return 0; 1154 1155 COMPtr<IWebViewEditing> viewEditing; 1156 if (FAILED(webView->QueryInterface(&viewEditing))) 1157 return 0; 1158 1159 if (FAILED(viewEditing->setEditingDelegate(sharedEditingDelegate.get()))) 1160 return 0; 1161 1162 if (FAILED(webView->setResourceLoadDelegate(sharedResourceLoadDelegate.get()))) 1163 return 0; 1164 1165 openWindows().append(hostWindow); 1166 windowToWebViewMap().set(hostWindow, webView); 1167 return webView; 1168 } 1169 1170 #if USE(CFNETWORK) 1171 RetainPtr<CFURLCacheRef> sharedCFURLCache() 1172 { 1173 #ifndef DEBUG_ALL 1174 HMODULE module = GetModuleHandle(TEXT("CFNetwork.dll")); 1175 #else 1176 HMODULE module = GetModuleHandle(TEXT("CFNetwork_debug.dll")); 1177 #endif 1178 if (!module) 1179 return 0; 1180 1181 typedef CFURLCacheRef (*CFURLCacheCopySharedURLCacheProcPtr)(void); 1182 if (CFURLCacheCopySharedURLCacheProcPtr copyCache = reinterpret_cast<CFURLCacheCopySharedURLCacheProcPtr>(GetProcAddress(module, "CFURLCacheCopySharedURLCache"))) 1183 return RetainPtr<CFURLCacheRef>(AdoptCF, copyCache()); 1184 1185 typedef CFURLCacheRef (*CFURLCacheSharedURLCacheProcPtr)(void); 1186 if (CFURLCacheSharedURLCacheProcPtr sharedCache = reinterpret_cast<CFURLCacheSharedURLCacheProcPtr>(GetProcAddress(module, "CFURLCacheSharedURLCache"))) 1187 return sharedCache(); 1188 1189 return 0; 1190 } 1191 #endif 1192 1193 int main(int argc, char* argv[]) 1194 { 1195 leakChecking = false; 1196 1197 _setmode(1, _O_BINARY); 1198 _setmode(2, _O_BINARY); 1199 1200 initialize(); 1201 1202 Vector<const char*> tests; 1203 1204 for (int i = 1; i < argc; ++i) { 1205 if (!stricmp(argv[i], "--threaded")) { 1206 threaded = true; 1207 continue; 1208 } 1209 1210 if (!stricmp(argv[i], "--dump-all-pixels")) { 1211 dumpAllPixels = true; 1212 continue; 1213 } 1214 1215 if (!stricmp(argv[i], "--pixel-tests")) { 1216 dumpPixels = true; 1217 continue; 1218 } 1219 1220 if (!stricmp(argv[i], "--complex-text")) { 1221 forceComplexText = true; 1222 continue; 1223 } 1224 1225 tests.append(argv[i]); 1226 } 1227 1228 policyDelegate = new PolicyDelegate(); 1229 sharedFrameLoadDelegate.adoptRef(new FrameLoadDelegate); 1230 sharedUIDelegate.adoptRef(new UIDelegate); 1231 sharedEditingDelegate.adoptRef(new EditingDelegate); 1232 sharedResourceLoadDelegate.adoptRef(new ResourceLoadDelegate); 1233 sharedHistoryDelegate.adoptRef(new HistoryDelegate); 1234 1235 // FIXME - need to make DRT pass with Windows native controls <http://bugs.webkit.org/show_bug.cgi?id=25592> 1236 COMPtr<IWebPreferences> tmpPreferences; 1237 if (FAILED(WebKitCreateInstance(CLSID_WebPreferences, 0, IID_IWebPreferences, reinterpret_cast<void**>(&tmpPreferences)))) 1238 return -1; 1239 COMPtr<IWebPreferences> standardPreferences; 1240 if (FAILED(tmpPreferences->standardPreferences(&standardPreferences))) 1241 return -1; 1242 COMPtr<IWebPreferencesPrivate> standardPreferencesPrivate; 1243 if (FAILED(standardPreferences->QueryInterface(&standardPreferencesPrivate))) 1244 return -1; 1245 standardPreferencesPrivate->setShouldPaintNativeControls(FALSE); 1246 standardPreferences->setJavaScriptEnabled(TRUE); 1247 standardPreferences->setDefaultFontSize(16); 1248 1249 COMPtr<IWebView> webView(AdoptCOM, createWebViewAndOffscreenWindow(&webViewWindow)); 1250 if (!webView) 1251 return -1; 1252 1253 COMPtr<IWebIconDatabase> iconDatabase; 1254 COMPtr<IWebIconDatabase> tmpIconDatabase; 1255 if (FAILED(WebKitCreateInstance(CLSID_WebIconDatabase, 0, IID_IWebIconDatabase, (void**)&tmpIconDatabase))) 1256 return -1; 1257 if (FAILED(tmpIconDatabase->sharedIconDatabase(&iconDatabase))) 1258 return -1; 1259 1260 if (FAILED(webView->mainFrame(&frame))) 1261 return -1; 1262 1263 #if USE(CFNETWORK) 1264 RetainPtr<CFURLCacheRef> urlCache = sharedCFURLCache(); 1265 CFURLCacheRemoveAllCachedResponses(urlCache.get()); 1266 #endif 1267 1268 #ifdef _DEBUG 1269 _CrtMemState entryToMainMemCheckpoint; 1270 if (leakChecking) 1271 _CrtMemCheckpoint(&entryToMainMemCheckpoint); 1272 #endif 1273 1274 if (threaded) 1275 startJavaScriptThreads(); 1276 1277 if (tests.size() == 1 && !strcmp(tests[0], "-")) { 1278 char filenameBuffer[2048]; 1279 printSeparators = true; 1280 while (fgets(filenameBuffer, sizeof(filenameBuffer), stdin)) { 1281 char* newLineCharacter = strchr(filenameBuffer, '\n'); 1282 if (newLineCharacter) 1283 *newLineCharacter = '\0'; 1284 1285 if (strlen(filenameBuffer) == 0) 1286 continue; 1287 1288 runTest(filenameBuffer); 1289 } 1290 } else { 1291 printSeparators = tests.size() > 1; 1292 for (int i = 0; i < tests.size(); i++) 1293 runTest(tests[i]); 1294 } 1295 1296 if (threaded) 1297 stopJavaScriptThreads(); 1298 1299 delete policyDelegate; 1300 frame->Release(); 1301 1302 #ifdef _DEBUG 1303 if (leakChecking) { 1304 // dump leaks to stderr 1305 _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE); 1306 _CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDERR); 1307 _CrtMemDumpAllObjectsSince(&entryToMainMemCheckpoint); 1308 } 1309 #endif 1310 1311 shutDownWebKit(); 1312 1313 return 0; 1314 } 1315