Home | History | Annotate | Download | only in win
      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(&currentItem)))
    588         return;
    589 
    590     assert(currentItem != prevTestBFItem);
    591     COMPtr<IUnknown> currentItemUnknown;
    592     currentItem->QueryInterface(&currentItemUnknown);
    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