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