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