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