76ddb2dfff6108a55ca768da7de55aff7c7838f0
[WebKit-https.git] / WebKitTools / DumpRenderTree / win / DumpRenderTree.cpp
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 #ifndef NDEBUG
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 #ifdef DEBUG_WEBKIT_HAS_SUFFIX
205 #define WEBKITDLL TEXT("WebKit_debug.dll")
206 #else
207 #define WEBKITDLL TEXT("WebKit.dll")
208 #endif
209
210 static void initialize()
211 {
212     if (HMODULE webKitModule = LoadLibrary(WEBKITDLL))
213         if (FARPROC dllRegisterServer = GetProcAddress(webKitModule, "DllRegisterServer"))
214             dllRegisterServer();
215
216     // Init COM
217     OleInitialize(0);
218
219     static LPCTSTR fontsToInstall[] = {
220         TEXT("AHEM____.ttf"),
221         TEXT("Apple Chancery.ttf"),
222         TEXT("Courier Bold.ttf"),
223         TEXT("Courier.ttf"),
224         TEXT("Helvetica Bold Oblique.ttf"),
225         TEXT("Helvetica Bold.ttf"),
226         TEXT("Helvetica Oblique.ttf"),
227         TEXT("Helvetica.ttf"),
228         TEXT("Helvetica Neue Bold Italic.ttf"),
229         TEXT("Helvetica Neue Bold.ttf"),
230         TEXT("Helvetica Neue Condensed Black.ttf"),
231         TEXT("Helvetica Neue Condensed Bold.ttf"),
232         TEXT("Helvetica Neue Italic.ttf"),
233         TEXT("Helvetica Neue Light Italic.ttf"),
234         TEXT("Helvetica Neue Light.ttf"),
235         TEXT("Helvetica Neue UltraLight Italic.ttf"),
236         TEXT("Helvetica Neue UltraLight.ttf"),
237         TEXT("Helvetica Neue.ttf"),
238         TEXT("Lucida Grande.ttf"),
239         TEXT("Lucida Grande Bold.ttf"),
240         TEXT("Monaco.ttf"),
241         TEXT("Papyrus.ttf"),
242         TEXT("Times Bold Italic.ttf"),
243         TEXT("Times Bold.ttf"),
244         TEXT("Times Italic.ttf"),
245         TEXT("Times Roman.ttf"),
246         TEXT("WebKit Layout Tests 2.ttf"),
247         TEXT("WebKit Layout Tests.ttf"),
248         TEXT("WebKitWeightWatcher100.ttf"),
249         TEXT("WebKitWeightWatcher200.ttf"),
250         TEXT("WebKitWeightWatcher300.ttf"),
251         TEXT("WebKitWeightWatcher400.ttf"),
252         TEXT("WebKitWeightWatcher500.ttf"),
253         TEXT("WebKitWeightWatcher600.ttf"),
254         TEXT("WebKitWeightWatcher700.ttf"),
255         TEXT("WebKitWeightWatcher800.ttf"),
256         TEXT("WebKitWeightWatcher900.ttf")
257     };
258
259     wstring resourcesPath = fontsPath();
260
261     COMPtr<IWebTextRenderer> textRenderer;
262     if (SUCCEEDED(WebKitCreateInstance(CLSID_WebTextRenderer, 0, IID_IWebTextRenderer, (void**)&textRenderer)))
263         for (int i = 0; i < ARRAYSIZE(fontsToInstall); ++i)
264             textRenderer->registerPrivateFont(wstring(resourcesPath + fontsToInstall[i]).c_str());
265
266     // Register a host window
267     WNDCLASSEX wcex;
268
269     wcex.cbSize = sizeof(WNDCLASSEX);
270
271     wcex.style         = CS_HREDRAW | CS_VREDRAW;
272     wcex.lpfnWndProc   = DumpRenderTreeWndProc;
273     wcex.cbClsExtra    = 0;
274     wcex.cbWndExtra    = 0;
275     wcex.hInstance     = GetModuleHandle(0);
276     wcex.hIcon         = 0;
277     wcex.hCursor       = LoadCursor(0, IDC_ARROW);
278     wcex.hbrBackground = 0;
279     wcex.lpszMenuName  = 0;
280     wcex.lpszClassName = kDumpRenderTreeClassName;
281     wcex.hIconSm       = 0;
282
283     RegisterClassEx(&wcex);
284 }
285
286 void displayWebView()
287 {
288     ::InvalidateRect(webViewWindow, 0, TRUE);
289     ::UpdateWindow(webViewWindow);
290 }
291
292 void dumpFrameScrollPosition(IWebFrame* frame)
293 {
294     if (!frame)
295         return;
296
297     COMPtr<IWebFramePrivate> framePrivate;
298     if (FAILED(frame->QueryInterface(&framePrivate)))
299         return;
300
301     SIZE scrollPosition;
302     if (FAILED(framePrivate->scrollOffset(&scrollPosition)))
303         return;
304
305     if (abs(scrollPosition.cx) > 0.00000001 || abs(scrollPosition.cy) > 0.00000001) {
306         COMPtr<IWebFrame> parent;
307         if (FAILED(frame->parentFrame(&parent)))
308             return;
309         if (parent) {
310             BSTR name;
311             if (FAILED(frame->name(&name)))
312                 return;
313             printf("frame '%S' ", name ? name : L"");
314             SysFreeString(name);
315         }
316         printf("scrolled to %.f,%.f\n", (double)scrollPosition.cx, (double)scrollPosition.cy);
317     }
318
319     if (::gLayoutTestController->dumpChildFrameScrollPositions()) {
320         COMPtr<IEnumVARIANT> enumKids;
321         if (FAILED(frame->childFrames(&enumKids)))
322             return;
323         VARIANT var;
324         VariantInit(&var);
325         while (enumKids->Next(1, &var, 0) == S_OK) {
326             ASSERT(V_VT(&var) == VT_UNKNOWN);
327             COMPtr<IWebFrame> framePtr;
328             V_UNKNOWN(&var)->QueryInterface(IID_IWebFrame, (void**)&framePtr);
329             dumpFrameScrollPosition(framePtr.get());
330             VariantClear(&var);
331         }
332     }
333 }
334
335 static wstring dumpFramesAsText(IWebFrame* frame)
336 {
337     if (!frame)
338         return L"";
339
340     COMPtr<IDOMDocument> document;
341     if (FAILED(frame->DOMDocument(&document)))
342         return L"";
343
344     COMPtr<IDOMElement> documentElement;
345     if (FAILED(document->documentElement(&documentElement)))
346         return L"";
347
348     wstring result;
349
350     // Add header for all but the main frame.
351     COMPtr<IWebFrame> parent;
352     if (FAILED(frame->parentFrame(&parent)))
353         return L"";
354     if (parent) {
355         BSTR name = L"";
356         if (FAILED(frame->name(&name)))
357             return L"";
358
359         result.append(L"\n--------\nFrame: '");
360         result.append(name ? name : L"", SysStringLen(name));
361         result.append(L"'\n--------\n");
362
363         SysFreeString(name);
364     }
365
366     BSTR innerText = 0;
367     COMPtr<IDOMElementPrivate> docPrivate;
368     if (SUCCEEDED(documentElement->QueryInterface(&docPrivate)))
369         docPrivate->innerText(&innerText);
370
371     result.append(innerText ? innerText : L"", SysStringLen(innerText));
372     result.append(L"\n");
373
374     SysFreeString(innerText);
375
376     if (::gLayoutTestController->dumpChildFramesAsText()) {
377         COMPtr<IEnumVARIANT> enumKids;
378         if (FAILED(frame->childFrames(&enumKids)))
379             return L"";
380         VARIANT var;
381         VariantInit(&var);
382         while (enumKids->Next(1, &var, 0) == S_OK) {
383             ASSERT(V_VT(&var) == VT_UNKNOWN);
384             COMPtr<IWebFrame> framePtr;
385             V_UNKNOWN(&var)->QueryInterface(IID_IWebFrame, (void**)&framePtr);
386             result.append(dumpFramesAsText(framePtr.get()));
387             VariantClear(&var);
388         }
389     }
390
391     return result;
392 }
393
394 static int compareHistoryItems(const void* item1, const void* item2)
395 {
396     COMPtr<IWebHistoryItemPrivate> itemA;
397     if (FAILED((*(COMPtr<IUnknown>*)item1)->QueryInterface(&itemA)))
398         return 0;
399
400     COMPtr<IWebHistoryItemPrivate> itemB;
401     if (FAILED((*(COMPtr<IUnknown>*)item2)->QueryInterface(&itemB)))
402         return 0;
403
404     BSTR targetA;
405     if (FAILED(itemA->target(&targetA)))
406         return 0;
407
408     BSTR targetB;
409     if (FAILED(itemB->target(&targetB))) {
410         SysFreeString(targetA);
411         return 0;
412     }
413
414     int result = wcsicmp(wstring(targetA, SysStringLen(targetA)).c_str(), wstring(targetB, SysStringLen(targetB)).c_str());
415     SysFreeString(targetA);
416     SysFreeString(targetB);
417     return result;
418 }
419
420 static void dumpHistoryItem(IWebHistoryItem* item, int indent, bool current)
421 {
422     assert(item);
423
424     int start = 0;
425     if (current) {
426         printf("curr->");
427         start = 6;
428     }
429     for (int i = start; i < indent; i++)
430         putchar(' ');
431
432     BSTR url;
433     if (FAILED(item->URLString(&url)))
434         return;
435
436     if (wcsstr(url, L"file:/") == url) {
437         static wchar_t* layoutTestsString = L"/LayoutTests/";
438         static wchar_t* fileTestString = L"(file test):";
439         
440         wchar_t* result = wcsstr(url, layoutTestsString);
441         if (result == NULL)
442             return;
443         wchar_t* start = result + wcslen(layoutTestsString);
444
445         BSTR newURL = SysAllocStringLen(NULL, SysStringLen(url));
446         wcscpy(newURL, fileTestString);
447         wcscpy(newURL + wcslen(fileTestString), start);
448
449         SysFreeString(url);
450         url = newURL;
451     }
452
453     printf("%S", url ? url : L"");
454     SysFreeString(url);
455
456     COMPtr<IWebHistoryItemPrivate> itemPrivate;
457     if (FAILED(item->QueryInterface(&itemPrivate)))
458         return;
459
460     BSTR target;
461     if (FAILED(itemPrivate->target(&target)))
462         return;
463     if (SysStringLen(target))
464         printf(" (in frame \"%S\")", target);
465     SysFreeString(target);
466     BOOL isTargetItem = FALSE;
467     if (FAILED(itemPrivate->isTargetItem(&isTargetItem)))
468         return;
469     if (isTargetItem)
470         printf("  **nav target**");
471     putchar('\n');
472
473     unsigned kidsCount;
474     SAFEARRAY* arrPtr;
475     if (FAILED(itemPrivate->children(&kidsCount, &arrPtr)) || !kidsCount)
476         return;
477
478     Vector<COMPtr<IUnknown> > kidsVector;
479
480     LONG lowerBound;
481     if (FAILED(::SafeArrayGetLBound(arrPtr, 1, &lowerBound)))
482         goto exit;
483
484     LONG upperBound;
485     if (FAILED(::SafeArrayGetUBound(arrPtr, 1, &upperBound)))
486         goto exit;
487
488     LONG length = upperBound - lowerBound + 1;
489     if (!length)
490         goto exit;
491     ASSERT(length == kidsCount);
492
493     IUnknown** safeArrayData;
494     if (FAILED(::SafeArrayAccessData(arrPtr, (void**)&safeArrayData)))
495         goto exit;
496
497     for (int i = 0; i < length; ++i)
498         kidsVector.append(safeArrayData[i]);
499     ::SafeArrayUnaccessData(arrPtr);
500
501     // must sort to eliminate arbitrary result ordering which defeats reproducible testing
502     qsort(kidsVector.data(), kidsCount, sizeof(kidsVector[0]), compareHistoryItems);
503
504     for (unsigned i = 0; i < kidsCount; ++i) {
505         COMPtr<IWebHistoryItem> item;
506         kidsVector[i]->QueryInterface(&item);
507         dumpHistoryItem(item.get(), indent + 4, false);
508     }
509
510 exit:
511     if (arrPtr && SUCCEEDED(::SafeArrayUnlock(arrPtr)))
512         ::SafeArrayDestroy(arrPtr);
513 }
514
515 static void dumpBackForwardList(IWebView* webView)
516 {
517     ASSERT(webView);
518
519     printf("\n============== Back Forward List ==============\n");
520
521     COMPtr<IWebBackForwardList> bfList;
522     if (FAILED(webView->backForwardList(&bfList)))
523         return;
524
525     // Print out all items in the list after prevTestBFItem, which was from the previous test
526     // Gather items from the end of the list, the print them out from oldest to newest
527
528     Vector<COMPtr<IUnknown> > itemsToPrint;
529
530     int forwardListCount;
531     if (FAILED(bfList->forwardListCount(&forwardListCount)))
532         return;
533
534     for (int i = forwardListCount; i > 0; --i) {
535         COMPtr<IWebHistoryItem> item;
536         if (FAILED(bfList->itemAtIndex(i, &item)))
537             return;
538         // something is wrong if the item from the last test is in the forward part of the b/f list
539         assert(item != prevTestBFItem);
540         COMPtr<IUnknown> itemUnknown;
541         item->QueryInterface(&itemUnknown);
542         itemsToPrint.append(itemUnknown);
543     }
544     
545     COMPtr<IWebHistoryItem> currentItem;
546     if (FAILED(bfList->currentItem(&currentItem)))
547         return;
548
549     assert(currentItem != prevTestBFItem);
550     COMPtr<IUnknown> currentItemUnknown;
551     currentItem->QueryInterface(&currentItemUnknown);
552     itemsToPrint.append(currentItemUnknown);
553     int currentItemIndex = itemsToPrint.size() - 1;
554
555     int backListCount;
556     if (FAILED(bfList->backListCount(&backListCount)))
557         return;
558
559     for (int i = -1; i >= -backListCount; --i) {
560         COMPtr<IWebHistoryItem> item;
561         if (FAILED(bfList->itemAtIndex(i, &item)))
562             return;
563         if (item == prevTestBFItem)
564             break;
565         COMPtr<IUnknown> itemUnknown;
566         item->QueryInterface(&itemUnknown);
567         itemsToPrint.append(itemUnknown);
568     }
569
570     for (int i = itemsToPrint.size() - 1; i >= 0; --i) {
571         COMPtr<IWebHistoryItem> historyItemToPrint;
572         itemsToPrint[i]->QueryInterface(&historyItemToPrint);
573         dumpHistoryItem(historyItemToPrint.get(), 8, i == currentItemIndex);
574     }
575
576     printf("===============================================\n");
577 }
578
579 static void dumpBackForwardListForAllWindows()
580 {
581     unsigned count = openWindows().size();
582     for (unsigned i = 0; i < count; i++) {
583         HWND window = openWindows()[i];
584         IWebView* webView = windowToWebViewMap().get(window).get();
585         dumpBackForwardList(webView);
586     }
587 }
588
589 static void invalidateAnyPreviousWaitToDumpWatchdog()
590 {
591     if (!waitToDumpWatchdog)
592         return;
593
594     KillTimer(0, waitToDumpWatchdog);
595     waitToDumpWatchdog = 0;
596 }
597
598 void dump()
599 {
600     invalidateAnyPreviousWaitToDumpWatchdog();
601
602     COMPtr<IWebDataSource> dataSource;
603     if (SUCCEEDED(frame->dataSource(&dataSource))) {
604         COMPtr<IWebURLResponse> response;
605         if (SUCCEEDED(dataSource->response(&response)) && response) {
606             BSTR mimeType;
607             if (SUCCEEDED(response->MIMEType(&mimeType)))
608                 ::gLayoutTestController->setDumpAsText(::gLayoutTestController->dumpAsText() | !_tcscmp(mimeType, TEXT("text/plain")));
609             SysFreeString(mimeType);
610         }
611     }
612
613     BSTR resultString = 0;
614
615     if (dumpTree) {
616         if (::gLayoutTestController->dumpAsText()) {
617             ::InvalidateRect(webViewWindow, 0, TRUE);
618             ::SendMessage(webViewWindow, WM_PAINT, 0, 0);
619             wstring result = dumpFramesAsText(frame);
620             resultString = SysAllocStringLen(result.data(), result.size());
621         } else {
622             bool isSVGW3CTest = (gLayoutTestController->testPathOrURL().find("svg\\W3C-SVG-1.1") != string::npos);
623             unsigned width;
624             unsigned height;
625             if (isSVGW3CTest) {
626                 width = 480;
627                 height = 360;
628             } else {
629                 width = maxViewWidth;
630                 height = maxViewHeight;
631             }
632
633             ::SetWindowPos(webViewWindow, 0, 0, 0, width, height, SWP_NOMOVE);
634             ::InvalidateRect(webViewWindow, 0, TRUE);
635             ::SendMessage(webViewWindow, WM_PAINT, 0, 0);
636
637             COMPtr<IWebFramePrivate> framePrivate;
638             if (FAILED(frame->QueryInterface(&framePrivate)))
639                 goto fail;
640             framePrivate->renderTreeAsExternalRepresentation(&resultString);
641         }
642         
643         if (!resultString)
644             printf("ERROR: nil result from %s", ::gLayoutTestController->dumpAsText() ? "IDOMElement::innerText" : "IFrameViewPrivate::renderTreeAsExternalRepresentation");
645         else {
646             unsigned stringLength = SysStringLen(resultString);
647             int bufferSize = ::WideCharToMultiByte(CP_UTF8, 0, resultString, stringLength, 0, 0, 0, 0);
648             char* buffer = (char*)malloc(bufferSize + 1);
649             ::WideCharToMultiByte(CP_UTF8, 0, resultString, stringLength, buffer, bufferSize + 1, 0, 0);
650             fwrite(buffer, 1, bufferSize, stdout);
651             free(buffer);
652             if (!::gLayoutTestController->dumpAsText())
653                 dumpFrameScrollPosition(frame);
654         }
655         if (::gLayoutTestController->dumpBackForwardList())
656             dumpBackForwardListForAllWindows();
657     }
658
659     if (printSeparators) {
660         puts("#EOF");   // terminate the content block
661         fputs("#EOF\n", stderr);
662         fflush(stdout);
663         fflush(stderr);
664     }
665
666     if (dumpPixels) {
667         if (!gLayoutTestController->dumpAsText() && !gLayoutTestController->dumpDOMAsWebArchive() && !gLayoutTestController->dumpSourceAsWebArchive())
668             dumpWebViewAsPixelsAndCompareWithExpected(gLayoutTestController->expectedPixelHash());
669     }
670
671     printf("#EOF\n");   // terminate the (possibly empty) pixels block
672     fflush(stdout);
673
674 fail:
675     SysFreeString(resultString);
676     // This will exit from our message loop.
677     PostQuitMessage(0);
678     done = true;
679 }
680
681 static bool shouldLogFrameLoadDelegates(const char* pathOrURL)
682 {
683     return strstr(pathOrURL, "/loading/") || strstr(pathOrURL, "\\loading\\");
684 }
685
686 static bool shouldLogHistoryDelegates(const char* pathOrURL)
687 {
688     return strstr(pathOrURL, "/globalhistory/") || strstr(pathOrURL, "\\globalhistory\\");
689 }
690
691 static void resetDefaultsToConsistentValues(IWebPreferences* preferences)
692 {
693 #ifdef USE_MAC_FONTS
694     static BSTR standardFamily = SysAllocString(TEXT("Times"));
695     static BSTR fixedFamily = SysAllocString(TEXT("Courier"));
696     static BSTR sansSerifFamily = SysAllocString(TEXT("Helvetica"));
697     static BSTR cursiveFamily = SysAllocString(TEXT("Apple Chancery"));
698     static BSTR fantasyFamily = SysAllocString(TEXT("Papyrus"));
699 #else
700     static BSTR standardFamily = SysAllocString(TEXT("Times New Roman"));
701     static BSTR fixedFamily = SysAllocString(TEXT("Courier New"));
702     static BSTR sansSerifFamily = SysAllocString(TEXT("Arial"));
703     static BSTR cursiveFamily = SysAllocString(TEXT("Comic Sans MS")); // Not actually cursive, but it's what IE and Firefox use.
704     static BSTR fantasyFamily = SysAllocString(TEXT("Times New Roman"));
705 #endif
706
707     preferences->setStandardFontFamily(standardFamily);
708     preferences->setFixedFontFamily(fixedFamily);
709     preferences->setSerifFontFamily(standardFamily);
710     preferences->setSansSerifFontFamily(sansSerifFamily);
711     preferences->setCursiveFontFamily(cursiveFamily);
712     preferences->setFantasyFontFamily(fantasyFamily);
713
714     preferences->setAutosaves(FALSE);
715     preferences->setDefaultFontSize(16);
716     preferences->setDefaultFixedFontSize(13);
717     preferences->setMinimumFontSize(1);
718     preferences->setJavaEnabled(FALSE);
719     preferences->setPlugInsEnabled(TRUE);
720     preferences->setDOMPasteAllowed(TRUE);
721     preferences->setEditableLinkBehavior(WebKitEditableLinkOnlyLiveWithShiftKey);
722     preferences->setFontSmoothing(FontSmoothingTypeStandard);
723     preferences->setUsesPageCache(FALSE);
724     preferences->setPrivateBrowsingEnabled(FALSE);
725     preferences->setJavaScriptCanOpenWindowsAutomatically(TRUE);
726     preferences->setJavaScriptEnabled(TRUE);
727     preferences->setTabsToLinks(FALSE);
728     preferences->setShouldPrintBackgrounds(TRUE);
729     preferences->setLoadsImagesAutomatically(TRUE);
730
731     if (persistentUserStyleSheetLocation) {
732         Vector<wchar_t> urlCharacters(CFStringGetLength(persistentUserStyleSheetLocation.get()));
733         CFStringGetCharacters(persistentUserStyleSheetLocation.get(), CFRangeMake(0, CFStringGetLength(persistentUserStyleSheetLocation.get())), (UniChar *)urlCharacters.data());
734         BSTR url = SysAllocStringLen(urlCharacters.data(), urlCharacters.size());
735         preferences->setUserStyleSheetLocation(url);
736         SysFreeString(url);
737         preferences->setUserStyleSheetEnabled(TRUE);
738     } else
739         preferences->setUserStyleSheetEnabled(FALSE);
740
741     COMPtr<IWebPreferencesPrivate> prefsPrivate(Query, preferences);
742     if (prefsPrivate) {
743         prefsPrivate->setAllowUniversalAccessFromFileURLs(TRUE);
744         prefsPrivate->setAuthorAndUserStylesEnabled(TRUE);
745         prefsPrivate->setDeveloperExtrasEnabled(FALSE);
746         prefsPrivate->setExperimentalNotificationsEnabled(TRUE);
747         prefsPrivate->setExperimentalWebSocketsEnabled(TRUE);
748         prefsPrivate->setShouldPaintNativeControls(FALSE); // FIXME - need to make DRT pass with Windows native controls <http://bugs.webkit.org/show_bug.cgi?id=25592>
749         prefsPrivate->setXSSAuditorEnabled(FALSE);
750         prefsPrivate->setOfflineWebApplicationCacheEnabled(TRUE);
751     }
752     setAlwaysAcceptCookies(false);
753
754     setlocale(LC_ALL, "");
755 }
756
757 static void resetWebViewToConsistentStateBeforeTesting()
758 {
759     COMPtr<IWebView> webView;
760     if (FAILED(frame->webView(&webView))) 
761         return;
762
763     webView->setPolicyDelegate(0);
764     policyDelegate->setPermissive(false);
765     policyDelegate->setControllerToNotifyDone(0);
766
767     COMPtr<IWebIBActions> webIBActions(Query, webView);
768     if (webIBActions) {
769         webIBActions->makeTextStandardSize(0);
770         webIBActions->resetPageZoom(0);
771     }
772
773
774     COMPtr<IWebPreferences> preferences;
775     if (SUCCEEDED(webView->preferences(&preferences)))
776         resetDefaultsToConsistentValues(preferences.get());
777
778     COMPtr<IWebViewEditing> viewEditing;
779     if (SUCCEEDED(webView->QueryInterface(&viewEditing)))
780         viewEditing->setSmartInsertDeleteEnabled(TRUE);
781
782     COMPtr<IWebViewPrivate> webViewPrivate(Query, webView);
783     if (!webViewPrivate)
784         return;
785
786     COMPtr<IWebInspector> inspector;
787     if (SUCCEEDED(webViewPrivate->inspector(&inspector)))
788         inspector->setJavaScriptProfilingEnabled(FALSE);
789
790     HWND viewWindow;
791     if (SUCCEEDED(webViewPrivate->viewWindow(reinterpret_cast<OLE_HANDLE*>(&viewWindow))) && viewWindow)
792         SetFocus(viewWindow);
793
794     webViewPrivate->clearMainFrameName();
795     webViewPrivate->resetOriginAccessWhiteLists();
796
797     sharedUIDelegate->resetUndoManager();
798
799     sharedFrameLoadDelegate->resetToConsistentState();
800 }
801
802 static void runTest(const string& testPathOrURL)
803 {
804     static BSTR methodBStr = SysAllocString(TEXT("GET"));
805
806     // Look for "'" as a separator between the path or URL, and the pixel dump hash that follows.
807     string pathOrURL(testPathOrURL);
808     string expectedPixelHash;
809     
810     size_t separatorPos = pathOrURL.find("'");
811     if (separatorPos != string::npos) {
812         pathOrURL = string(testPathOrURL, 0, separatorPos);
813         expectedPixelHash = string(testPathOrURL, separatorPos + 1);
814     }
815     
816     BSTR urlBStr;
817  
818     CFStringRef str = CFStringCreateWithCString(0, pathOrURL.c_str(), kCFStringEncodingWindowsLatin1);
819     CFURLRef url = CFURLCreateWithString(0, str, 0);
820
821     if (!url)
822         url = CFURLCreateWithFileSystemPath(0, str, kCFURLWindowsPathStyle, false);
823
824     CFRelease(str);
825
826     str = CFURLGetString(url);
827
828     CFIndex length = CFStringGetLength(str);
829     UniChar* buffer = new UniChar[length];
830
831     CFStringGetCharacters(str, CFRangeMake(0, length), buffer);
832     urlBStr = SysAllocStringLen((OLECHAR*)buffer, length);
833     delete[] buffer;
834
835     CFRelease(url);
836
837     ::gLayoutTestController = new LayoutTestController(pathOrURL, expectedPixelHash);
838     done = false;
839     topLoadingFrame = 0;
840
841     gLayoutTestController->setIconDatabaseEnabled(false);
842
843     if (shouldLogFrameLoadDelegates(pathOrURL.c_str()))
844         gLayoutTestController->setDumpFrameLoadCallbacks(true);
845
846     COMPtr<IWebView> webView;
847     if (SUCCEEDED(frame->webView(&webView))) {
848         COMPtr<IWebViewPrivate> viewPrivate;
849         if (SUCCEEDED(webView->QueryInterface(&viewPrivate))) {
850             if (shouldLogHistoryDelegates(pathOrURL.c_str())) {
851                 gLayoutTestController->setDumpHistoryDelegateCallbacks(true);            
852                 viewPrivate->setHistoryDelegate(sharedHistoryDelegate.get());
853             } else
854                 viewPrivate->setHistoryDelegate(0);
855         }
856     }
857     COMPtr<IWebHistory> history;
858     if (SUCCEEDED(WebKitCreateInstance(CLSID_WebHistory, 0, __uuidof(history), reinterpret_cast<void**>(&history))))
859         history->setOptionalSharedHistory(0);
860
861     resetWebViewToConsistentStateBeforeTesting();
862
863     prevTestBFItem = 0;
864     if (webView) {
865         COMPtr<IWebBackForwardList> bfList;
866         if (SUCCEEDED(webView->backForwardList(&bfList)))
867             bfList->currentItem(&prevTestBFItem);
868     }
869
870     WorkQueue::shared()->clear();
871     WorkQueue::shared()->setFrozen(false);
872
873     HWND hostWindow;
874     webView->hostWindow(reinterpret_cast<OLE_HANDLE*>(&hostWindow));
875
876     COMPtr<IWebMutableURLRequest> request;
877     HRESULT hr = WebKitCreateInstance(CLSID_WebMutableURLRequest, 0, IID_IWebMutableURLRequest, (void**)&request);
878     if (FAILED(hr))
879         goto exit;
880
881     request->initWithURL(urlBStr, WebURLRequestUseProtocolCachePolicy, 60);
882
883     request->setHTTPMethod(methodBStr);
884     frame->loadRequest(request.get());
885
886     MSG msg;
887     while (GetMessage(&msg, 0, 0, 0)) {
888         // We get spurious WM_MOUSELEAVE events which make event handling machinery think that mouse button
889         // is released during dragging (see e.g. fast\dynamic\layer-hit-test-crash.html).
890         // Mouse can never leave WebView during normal DumpRenderTree operation, so we just ignore all such events.
891         if (msg.message == WM_MOUSELEAVE)
892             continue;
893         TranslateMessage(&msg);
894         DispatchMessage(&msg);
895     }
896
897     resetWebViewToConsistentStateBeforeTesting();
898
899     frame->stopLoading();
900
901     if (::gLayoutTestController->closeRemainingWindowsWhenComplete()) {
902         Vector<HWND> windows = openWindows();
903         unsigned size = windows.size();
904         for (unsigned i = 0; i < size; i++) {
905             HWND window = windows[i];
906
907             // Don't try to close the main window
908             if (window == hostWindow)
909                 continue;
910
911             DestroyWindow(window);
912         }
913     }
914
915 exit:
916     SysFreeString(urlBStr);
917     ::gLayoutTestController->deref();
918     ::gLayoutTestController = 0;
919
920     return;
921 }
922
923 static Boolean pthreadEqualCallback(const void* value1, const void* value2)
924 {
925     return (Boolean)pthread_equal(*(pthread_t*)value1, *(pthread_t*)value2);
926 }
927
928 static CFDictionaryKeyCallBacks pthreadKeyCallbacks = { 0, 0, 0, 0, pthreadEqualCallback, 0 };
929
930 static pthread_mutex_t javaScriptThreadsMutex = PTHREAD_MUTEX_INITIALIZER;
931 static bool javaScriptThreadsShouldTerminate;
932
933 static const int javaScriptThreadsCount = 4;
934 static CFMutableDictionaryRef javaScriptThreads()
935 {
936     assert(pthread_mutex_trylock(&javaScriptThreadsMutex) == EBUSY);
937     static CFMutableDictionaryRef staticJavaScriptThreads;
938     if (!staticJavaScriptThreads)
939         staticJavaScriptThreads = CFDictionaryCreateMutable(0, 0, &pthreadKeyCallbacks, 0);
940     return staticJavaScriptThreads;
941 }
942
943 // Loops forever, running a script and randomly respawning, until 
944 // javaScriptThreadsShouldTerminate becomes true.
945 void* runJavaScriptThread(void* arg)
946 {
947     const char* const script =
948     " \
949     var array = []; \
950     for (var i = 0; i < 10; i++) { \
951         array.push(String(i)); \
952     } \
953     ";
954
955     while (true) {
956         JSGlobalContextRef ctx = JSGlobalContextCreate(0);
957         JSStringRef scriptRef = JSStringCreateWithUTF8CString(script);
958
959         JSValueRef exception = 0;
960         JSEvaluateScript(ctx, scriptRef, 0, 0, 1, &exception);
961         assert(!exception);
962         
963         JSGlobalContextRelease(ctx);
964         JSStringRelease(scriptRef);
965         
966         JSGarbageCollect(ctx);
967
968         pthread_mutex_lock(&javaScriptThreadsMutex);
969
970         // Check for cancellation.
971         if (javaScriptThreadsShouldTerminate) {
972             pthread_mutex_unlock(&javaScriptThreadsMutex);
973             return 0;
974         }
975
976         // Respawn probabilistically.
977         if (rand() % 5 == 0) {
978             pthread_t pthread;
979             pthread_create(&pthread, 0, &runJavaScriptThread, 0);
980             pthread_detach(pthread);
981
982             pthread_t self = pthread_self();
983             CFDictionaryRemoveValue(javaScriptThreads(), self.p);
984             CFDictionaryAddValue(javaScriptThreads(), pthread.p, 0);
985
986             pthread_mutex_unlock(&javaScriptThreadsMutex);
987             return 0;
988         }
989
990         pthread_mutex_unlock(&javaScriptThreadsMutex);
991     }
992 }
993
994 static void startJavaScriptThreads(void)
995 {
996     pthread_mutex_lock(&javaScriptThreadsMutex);
997
998     for (int i = 0; i < javaScriptThreadsCount; i++) {
999         pthread_t pthread;
1000         pthread_create(&pthread, 0, &runJavaScriptThread, 0);
1001         pthread_detach(pthread);
1002         CFDictionaryAddValue(javaScriptThreads(), pthread.p, 0);
1003     }
1004
1005     pthread_mutex_unlock(&javaScriptThreadsMutex);
1006 }
1007
1008 static void stopJavaScriptThreads(void)
1009 {
1010     pthread_mutex_lock(&javaScriptThreadsMutex);
1011
1012     javaScriptThreadsShouldTerminate = true;
1013
1014     pthread_t* pthreads[javaScriptThreadsCount] = {0};
1015     int threadDictCount = CFDictionaryGetCount(javaScriptThreads());
1016     assert(threadDictCount == javaScriptThreadsCount);
1017     CFDictionaryGetKeysAndValues(javaScriptThreads(), (const void**)pthreads, 0);
1018
1019     pthread_mutex_unlock(&javaScriptThreadsMutex);
1020
1021     for (int i = 0; i < javaScriptThreadsCount; i++) {
1022         pthread_t* pthread = pthreads[i];
1023         pthread_join(*pthread, 0);
1024         free(pthread);
1025     }
1026 }
1027
1028 Vector<HWND>& openWindows()
1029 {
1030     static Vector<HWND> vector;
1031     return vector;
1032 }
1033
1034 WindowToWebViewMap& windowToWebViewMap()
1035 {
1036     static WindowToWebViewMap map;
1037     return map;
1038 }
1039
1040 IWebView* createWebViewAndOffscreenWindow(HWND* webViewWindow)
1041 {
1042     HWND hostWindow = CreateWindowEx(WS_EX_TOOLWINDOW, kDumpRenderTreeClassName, TEXT("DumpRenderTree"), WS_POPUP,
1043       -maxViewWidth, -maxViewHeight, maxViewWidth, maxViewHeight, 0, 0, GetModuleHandle(0), 0);
1044
1045     IWebView* webView;
1046
1047     HRESULT hr = WebKitCreateInstance(CLSID_WebView, 0, IID_IWebView, (void**)&webView);
1048     if (FAILED(hr)) {
1049         fprintf(stderr, "Failed to create CLSID_WebView instance, error 0x%x\n", hr);
1050         return 0;
1051     }
1052
1053     if (FAILED(webView->setHostWindow((OLE_HANDLE)(ULONG64)hostWindow)))
1054         return 0;
1055
1056     RECT clientRect;
1057     clientRect.bottom = clientRect.left = clientRect.top = clientRect.right = 0;
1058     BSTR groupName = SysAllocString(L"org.webkit.DumpRenderTree");
1059     bool failed = FAILED(webView->initWithFrame(clientRect, 0, groupName));
1060     SysFreeString(groupName);
1061     if (failed)
1062         return 0;
1063
1064     COMPtr<IWebViewPrivate> viewPrivate;
1065     if (FAILED(webView->QueryInterface(&viewPrivate)))
1066         return 0;
1067
1068     viewPrivate->setShouldApplyMacFontAscentHack(TRUE);
1069     viewPrivate->setAlwaysUsesComplexTextCodePath(forceComplexText);
1070
1071     BSTR pluginPath = SysAllocStringLen(0, exePath().length() + _tcslen(TestPluginDir));
1072     _tcscpy(pluginPath, exePath().c_str());
1073     _tcscat(pluginPath, TestPluginDir);
1074     failed = FAILED(viewPrivate->addAdditionalPluginDirectory(pluginPath));
1075     SysFreeString(pluginPath);
1076     if (failed)
1077         return 0;
1078
1079     HWND viewWindow;
1080     if (FAILED(viewPrivate->viewWindow(reinterpret_cast<OLE_HANDLE*>(&viewWindow))))
1081         return 0;
1082     if (webViewWindow)
1083         *webViewWindow = viewWindow;
1084
1085     SetWindowPos(viewWindow, 0, 0, 0, maxViewWidth, maxViewHeight, 0);
1086     ShowWindow(hostWindow, SW_SHOW);
1087
1088     if (FAILED(webView->setFrameLoadDelegate(sharedFrameLoadDelegate.get())))
1089         return 0;
1090
1091     if (FAILED(viewPrivate->setFrameLoadDelegatePrivate(sharedFrameLoadDelegate.get())))
1092         return 0;
1093
1094     if (FAILED(webView->setUIDelegate(sharedUIDelegate.get())))
1095         return 0;
1096
1097     COMPtr<IWebViewEditing> viewEditing;
1098     if (FAILED(webView->QueryInterface(&viewEditing)))
1099         return 0;
1100
1101     if (FAILED(viewEditing->setEditingDelegate(sharedEditingDelegate.get())))
1102         return 0;
1103
1104     if (FAILED(webView->setResourceLoadDelegate(sharedResourceLoadDelegate.get())))
1105         return 0;
1106
1107     openWindows().append(hostWindow);
1108     windowToWebViewMap().set(hostWindow, webView);
1109     return webView;
1110 }
1111
1112 #if USE(CFNETWORK)
1113 RetainPtr<CFURLCacheRef> sharedCFURLCache()
1114 {
1115     HMODULE module = GetModuleHandle(TEXT("CFNetwork_debug.dll"));
1116     if (!module)
1117         module = GetModuleHandle(TEXT("CFNetwork.dll"));
1118     if (!module)
1119         return 0;
1120
1121     typedef CFURLCacheRef (*CFURLCacheCopySharedURLCacheProcPtr)(void);
1122     if (CFURLCacheCopySharedURLCacheProcPtr copyCache = reinterpret_cast<CFURLCacheCopySharedURLCacheProcPtr>(GetProcAddress(module, "CFURLCacheCopySharedURLCache")))
1123         return RetainPtr<CFURLCacheRef>(AdoptCF, copyCache());
1124
1125     typedef CFURLCacheRef (*CFURLCacheSharedURLCacheProcPtr)(void);
1126     if (CFURLCacheSharedURLCacheProcPtr sharedCache = reinterpret_cast<CFURLCacheSharedURLCacheProcPtr>(GetProcAddress(module, "CFURLCacheSharedURLCache")))
1127         return sharedCache();
1128
1129     return 0;
1130 }
1131 #endif
1132
1133 int main(int argc, char* argv[])
1134 {
1135     leakChecking = false;
1136
1137     _setmode(1, _O_BINARY);
1138     _setmode(2, _O_BINARY);
1139
1140     initialize();
1141
1142     Vector<const char*> tests;
1143
1144     for (int i = 1; i < argc; ++i) {
1145         if (!stricmp(argv[i], "--threaded")) {
1146             threaded = true;
1147             continue;
1148         }
1149
1150         if (!stricmp(argv[i], "--dump-all-pixels")) {
1151             dumpAllPixels = true;
1152             continue;
1153         }
1154
1155         if (!stricmp(argv[i], "--pixel-tests")) {
1156             dumpPixels = true;
1157             continue;
1158         }
1159
1160         if (!stricmp(argv[i], "--complex-text")) {
1161             forceComplexText = true;
1162             continue;
1163         }
1164
1165         tests.append(argv[i]);
1166     }
1167
1168     policyDelegate = new PolicyDelegate();
1169     sharedFrameLoadDelegate.adoptRef(new FrameLoadDelegate);
1170     sharedUIDelegate.adoptRef(new UIDelegate);
1171     sharedEditingDelegate.adoptRef(new EditingDelegate);
1172     sharedResourceLoadDelegate.adoptRef(new ResourceLoadDelegate);
1173     sharedHistoryDelegate.adoptRef(new HistoryDelegate);
1174
1175     // FIXME - need to make DRT pass with Windows native controls <http://bugs.webkit.org/show_bug.cgi?id=25592>
1176     COMPtr<IWebPreferences> tmpPreferences;
1177     if (FAILED(WebKitCreateInstance(CLSID_WebPreferences, 0, IID_IWebPreferences, reinterpret_cast<void**>(&tmpPreferences))))
1178         return -1;
1179     COMPtr<IWebPreferences> standardPreferences;
1180     if (FAILED(tmpPreferences->standardPreferences(&standardPreferences)))
1181         return -1;
1182     COMPtr<IWebPreferencesPrivate> standardPreferencesPrivate;
1183     if (FAILED(standardPreferences->QueryInterface(&standardPreferencesPrivate)))
1184         return -1;
1185     standardPreferencesPrivate->setShouldPaintNativeControls(FALSE);
1186     standardPreferences->setJavaScriptEnabled(TRUE);
1187     standardPreferences->setDefaultFontSize(16);
1188
1189     COMPtr<IWebView> webView(AdoptCOM, createWebViewAndOffscreenWindow(&webViewWindow));
1190     if (!webView)
1191         return -1;
1192
1193     COMPtr<IWebIconDatabase> iconDatabase;
1194     COMPtr<IWebIconDatabase> tmpIconDatabase;
1195     if (FAILED(WebKitCreateInstance(CLSID_WebIconDatabase, 0, IID_IWebIconDatabase, (void**)&tmpIconDatabase)))
1196         return -1;
1197     if (FAILED(tmpIconDatabase->sharedIconDatabase(&iconDatabase)))
1198         return -1;
1199         
1200     if (FAILED(webView->mainFrame(&frame)))
1201         return -1;
1202
1203 #if USE(CFNETWORK)
1204     RetainPtr<CFURLCacheRef> urlCache = sharedCFURLCache();
1205     CFURLCacheRemoveAllCachedResponses(urlCache.get());
1206 #endif
1207
1208 #ifdef _DEBUG
1209     _CrtMemState entryToMainMemCheckpoint;
1210     if (leakChecking)
1211         _CrtMemCheckpoint(&entryToMainMemCheckpoint);
1212 #endif
1213
1214     if (threaded)
1215         startJavaScriptThreads();
1216
1217     if (tests.size() == 1 && !strcmp(tests[0], "-")) {
1218         char filenameBuffer[2048];
1219         printSeparators = true;
1220         while (fgets(filenameBuffer, sizeof(filenameBuffer), stdin)) {
1221             char* newLineCharacter = strchr(filenameBuffer, '\n');
1222             if (newLineCharacter)
1223                 *newLineCharacter = '\0';
1224             
1225             if (strlen(filenameBuffer) == 0)
1226                 continue;
1227
1228             runTest(filenameBuffer);
1229         }
1230     } else {
1231         printSeparators = tests.size() > 1;
1232         for (int i = 0; i < tests.size(); i++)
1233             runTest(tests[i]);
1234     }
1235
1236     if (threaded)
1237         stopJavaScriptThreads();
1238     
1239     delete policyDelegate;
1240     frame->Release();
1241
1242 #ifdef _DEBUG
1243     if (leakChecking) {
1244         // dump leaks to stderr
1245         _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE);
1246         _CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDERR);
1247         _CrtMemDumpAllObjectsSince(&entryToMainMemCheckpoint);
1248     }
1249 #endif
1250
1251     shutDownWebKit();
1252
1253     return 0;
1254 }