2 * Copyright (C) 2005, 2006, 2007 Apple Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
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.
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.
29 #include "DumpRenderTree.h"
31 #include "EditingDelegate.h"
32 #include "FrameLoaderDelegate.h"
33 #include "LayoutTestController.h"
34 #include "UIDelegate.h"
35 #include "WorkQueueItem.h"
36 #include "WorkQueue.h"
37 #include <wtf/Vector.h>
38 #include <WebCore/COMPtr.h>
39 #include <CoreFoundation/CoreFoundation.h>
40 #include <JavaScriptCore/JavaScriptCore.h>
45 #include <WebKitInitializer/WebKitInitializer.h>
46 #include <WebKit/DOMPrivate.h>
47 #include <WebKit/IWebFramePrivate.h>
48 #include <WebKit/IWebHistoryItem.h>
49 #include <WebKit/IWebHistoryItemPrivate.h>
50 #include <WebKit/IWebURLResponse.h>
51 #include <WebKit/IWebViewPrivate.h>
52 #include <WebKit/WebKit.h>
59 const LPWSTR TestPluginDir = L"TestNetscapePlugin_Debug";
61 const LPWSTR TestPluginDir = L"TestNetscapePlugin";
66 const LPCWSTR kDumpRenderTreeClassName = L"DumpRenderTreeWindow";
68 static bool dumpTree = true;
69 static bool printSeparators;
70 static bool leakChecking = false;
71 static bool timedOut = false;
72 static bool threaded = false;
74 static const char* currentTest;
77 // This is the topmost frame that is loading, during a given load, or nil when no load is
78 // in progress. Usually this is the same as the main frame, but not always. In the case
79 // where a frameset is loaded, and then new content is loaded into one of the child frames,
80 // that child frame is the "topmost frame that is loading".
81 IWebFrame* topLoadingFrame; // !nil iff a load is in progress
82 static COMPtr<IWebHistoryItem> prevTestBFItem; // current b/f item at the end of the previous test
86 static HWND hostWindow;
88 LayoutTestController* layoutTestController = 0;
89 CFRunLoopTimerRef waitToDumpWatchdog = 0;
91 static const unsigned timeoutValue = 60000;
92 static const unsigned timeoutId = 10;
94 const unsigned maxViewWidth = 800;
95 const unsigned maxViewHeight = 600;
97 static LRESULT CALLBACK DumpRenderTreeWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
101 // The test ran long enough to time out
107 return DefWindowProc(hWnd, msg, wParam, lParam);
111 extern "C" BOOL InitializeCoreGraphics();
113 static wstring initialize(HMODULE hModule)
115 if (!initializeWebKit()) {
116 fprintf(stderr, "WebKit failed to initialize\n");
120 static LPCTSTR fontsToInstall[] = {
121 TEXT("AHEM____.ttf"),
122 TEXT("Apple Chancery.ttf"),
123 TEXT("Courier Bold.ttf"),
125 TEXT("Helvetica Bold.ttf"),
126 TEXT("Helvetica.ttf"),
127 TEXT("Helvetica Neue Bold Italic.ttf"),
128 TEXT("Helvetica Neue Bold.ttf"),
129 TEXT("Helvetica Neue Condensed Black.ttf"),
130 TEXT("Helvetica Neue Condensed Bold.ttf"),
131 TEXT("Helvetica Neue Italic.ttf"),
132 TEXT("Helvetica Neue Light Italic.ttf"),
133 TEXT("Helvetica Neue Light.ttf"),
134 TEXT("Helvetica Neue UltraLight Italic.ttf"),
135 TEXT("Helvetica Neue UltraLight.ttf"),
136 TEXT("Helvetica Neue.ttf"),
137 TEXT("Lucida Grande.ttf"),
138 TEXT("Lucida Grande Bold.ttf"),
141 TEXT("Times Bold Italic.ttf"),
142 TEXT("Times Bold.ttf"),
143 TEXT("Times Italic.ttf"),
144 TEXT("Times Roman.ttf")
147 TCHAR buffer[MAX_PATH];
148 GetModuleFileName(hModule, buffer, ARRAYSIZE(buffer));
149 wstring exePath(buffer);
150 int lastSlash = exePath.rfind('\\');
151 if (lastSlash != -1 && lastSlash + 1< exePath.length())
152 exePath = exePath.substr(0, lastSlash + 1);
154 wstring resourcesPath(exePath + TEXT("DumpRenderTree.resources\\"));
156 for (int i = 0; i < ARRAYSIZE(fontsToInstall); ++i)
157 AddFontResourceEx(wstring(resourcesPath + fontsToInstall[i]).c_str(), FR_PRIVATE, 0);
163 InitializeCoreGraphics();
165 // Register a host window
168 wcex.cbSize = sizeof(WNDCLASSEX);
170 wcex.style = CS_HREDRAW | CS_VREDRAW;
171 wcex.lpfnWndProc = DumpRenderTreeWndProc;
174 wcex.hInstance = hModule;
176 wcex.hCursor = LoadCursor(0, IDC_ARROW);
177 wcex.hbrBackground = 0;
178 wcex.lpszMenuName = 0;
179 wcex.lpszClassName = kDumpRenderTreeClassName;
182 RegisterClassEx(&wcex);
184 hostWindow = CreateWindowEx(WS_EX_TOOLWINDOW, kDumpRenderTreeClassName, TEXT("DumpRenderTree"), WS_POPUP,
185 -maxViewWidth, -maxViewHeight, maxViewWidth, maxViewHeight, 0, 0, hModule, 0);
190 void displayWebView()
192 ::InvalidateRect(webViewWindow, 0, TRUE);
193 ::UpdateWindow(webViewWindow);
196 void dumpFrameScrollPosition(IWebFrame* frame)
201 COMPtr<IWebFramePrivate> framePrivate;
202 if (FAILED(frame->QueryInterface(&framePrivate)))
206 if (FAILED(framePrivate->scrollOffset(&scrollPosition)))
209 if (abs(scrollPosition.cx) > 0.00000001 || abs(scrollPosition.cy) > 0.00000001) {
210 COMPtr<IWebFrame> parent;
211 if (FAILED(frame->parentFrame(&parent)))
215 if (FAILED(frame->name(&name)))
217 printf("frame '%S' ", name ? name : L"");
220 printf("scrolled to %.f,%.f\n", (double)scrollPosition.cx, (double)scrollPosition.cy);
223 if (::layoutTestController->dumpChildFrameScrollPositions()) {
224 COMPtr<IEnumVARIANT> enumKids;
225 if (FAILED(frame->childFrames(&enumKids)))
229 while (enumKids->Next(1, &var, 0) == S_OK) {
230 ASSERT(V_VT(&var) == VT_UNKNOWN);
231 COMPtr<IWebFrame> framePtr;
232 V_UNKNOWN(&var)->QueryInterface(IID_IWebFrame, (void**)&framePtr);
233 dumpFrameScrollPosition(framePtr.get());
239 static wstring dumpFramesAsText(IWebFrame* frame)
244 COMPtr<IDOMDocument> document;
245 if (FAILED(frame->DOMDocument(&document)))
248 COMPtr<IDOMElement> documentElement;
249 if (FAILED(document->documentElement(&documentElement)))
254 // Add header for all but the main frame.
255 COMPtr<IWebFrame> parent;
256 if (FAILED(frame->parentFrame(&parent)))
260 if (FAILED(frame->name(&name)))
263 result.append(L"\n--------\nFrame: '");
264 result.append(name ? name : L"");
265 result.append(L"'\n--------\n");
271 COMPtr<IDOMElementPrivate> docPrivate;
272 if (SUCCEEDED(documentElement->QueryInterface(&docPrivate)))
273 docPrivate->innerText(&innerText);
275 result.append(innerText ? innerText : L"");
276 result.append(L"\n");
278 SysFreeString(innerText);
280 if (::layoutTestController->dumpChildFramesAsText()) {
281 COMPtr<IEnumVARIANT> enumKids;
282 if (FAILED(frame->childFrames(&enumKids)))
286 while (enumKids->Next(1, &var, 0) == S_OK) {
287 ASSERT(V_VT(&var) == VT_UNKNOWN);
288 COMPtr<IWebFrame> framePtr;
289 V_UNKNOWN(&var)->QueryInterface(IID_IWebFrame, (void**)&framePtr);
290 result.append(dumpFramesAsText(framePtr.get()));
298 static int compareHistoryItems(const void* item1, const void* item2)
300 COMPtr<IWebHistoryItemPrivate> itemA;
301 if (FAILED((*(COMPtr<IUnknown>*)item1)->QueryInterface(&itemA)))
304 COMPtr<IWebHistoryItemPrivate> itemB;
305 if (FAILED((*(COMPtr<IUnknown>*)item2)->QueryInterface(&itemB)))
309 if (FAILED(itemA->target(&targetA)))
313 if (FAILED(itemB->target(&targetB))) {
314 SysFreeString(targetA);
318 int result = wcsicmp(wstring(targetA, SysStringLen(targetA)).c_str(), wstring(targetB, SysStringLen(targetB)).c_str());
319 SysFreeString(targetA);
320 SysFreeString(targetB);
324 static void dumpHistoryItem(IWebHistoryItem* item, int indent, bool current)
333 for (int i = start; i < indent; i++)
337 if (FAILED(item->URLString(&url)))
339 printf("%S", url ? url : L"");
342 COMPtr<IWebHistoryItemPrivate> itemPrivate;
343 if (FAILED(item->QueryInterface(&itemPrivate)))
347 if (FAILED(itemPrivate->target(&target)))
349 if (SysStringLen(target))
350 printf(" (in frame \"%S\")", target);
351 SysFreeString(target);
352 BOOL isTargetItem = FALSE;
353 if (FAILED(itemPrivate->isTargetItem(&isTargetItem)))
356 printf(" **nav target**");
361 if (FAILED(itemPrivate->children(&kidsCount, &arrPtr)) || !kidsCount)
364 Vector<COMPtr<IUnknown> > kidsVector;
367 if (FAILED(::SafeArrayGetLBound(arrPtr, 1, &lowerBound)))
371 if (FAILED(::SafeArrayGetUBound(arrPtr, 1, &upperBound)))
374 LONG length = upperBound - lowerBound + 1;
377 ASSERT(length == kidsCount);
379 IUnknown** safeArrayData;
380 if (FAILED(::SafeArrayAccessData(arrPtr, (void**)&safeArrayData)))
383 for (int i = 0; i < length; ++i)
384 kidsVector.append(safeArrayData[i]);
385 ::SafeArrayUnaccessData(arrPtr);
387 // must sort to eliminate arbitrary result ordering which defeats reproducible testing
388 qsort(kidsVector.data(), kidsCount, sizeof(kidsVector[0]), compareHistoryItems);
390 for (unsigned i = 0; i < kidsCount; ++i) {
391 COMPtr<IWebHistoryItem> item;
392 kidsVector[i]->QueryInterface(&item);
393 dumpHistoryItem(item.get(), indent + 4, false);
397 if (arrPtr && SUCCEEDED(::SafeArrayUnlock(arrPtr)))
398 ::SafeArrayDestroy(arrPtr);
401 static void dumpBackForwardList(IWebFrame* frame)
405 printf("\n============== Back Forward List ==============\n");
406 COMPtr<IWebView> webView;
407 if (FAILED(frame->webView(&webView)))
410 COMPtr<IWebBackForwardList> bfList;
411 if (FAILED(webView->backForwardList(&bfList)))
414 // Print out all items in the list after prevTestBFItem, which was from the previous test
415 // Gather items from the end of the list, the print them out from oldest to newest
417 Vector<COMPtr<IUnknown> > itemsToPrint;
419 int forwardListCount;
420 if (FAILED(bfList->forwardListCount(&forwardListCount)))
423 for (int i = forwardListCount; i > 0; --i) {
424 COMPtr<IWebHistoryItem> item;
425 if (FAILED(bfList->itemAtIndex(i, &item)))
427 // something is wrong if the item from the last test is in the forward part of the b/f list
428 assert(item != prevTestBFItem);
429 COMPtr<IUnknown> itemUnknown;
430 item->QueryInterface(&itemUnknown);
431 itemsToPrint.append(itemUnknown);
434 COMPtr<IWebHistoryItem> currentItem;
435 if (FAILED(bfList->currentItem(¤tItem)))
438 assert(currentItem != prevTestBFItem);
439 COMPtr<IUnknown> currentItemUnknown;
440 currentItem->QueryInterface(¤tItemUnknown);
441 itemsToPrint.append(currentItemUnknown);
442 int currentItemIndex = itemsToPrint.size() - 1;
445 if (FAILED(bfList->backListCount(&backListCount)))
448 for (int i = -1; i >= -backListCount; --i) {
449 COMPtr<IWebHistoryItem> item;
450 if (FAILED(bfList->itemAtIndex(i, &item)))
452 if (item == prevTestBFItem)
454 COMPtr<IUnknown> itemUnknown;
455 item->QueryInterface(&itemUnknown);
456 itemsToPrint.append(itemUnknown);
459 for (int i = itemsToPrint.size() - 1; i >= 0; --i) {
460 COMPtr<IWebHistoryItem> historyItemToPrint;
461 itemsToPrint[i]->QueryInterface(&historyItemToPrint);
462 dumpHistoryItem(historyItemToPrint.get(), 8, i == currentItemIndex);
465 printf("===============================================\n");
470 COMPtr<IWebDataSource> dataSource;
471 if (SUCCEEDED(frame->dataSource(&dataSource))) {
472 COMPtr<IWebURLResponse> response;
473 if (SUCCEEDED(dataSource->response(&response)) && response) {
475 if (SUCCEEDED(response->MIMEType(&mimeType)))
476 ::layoutTestController->setDumpAsText(::layoutTestController->dumpAsText() | !_tcscmp(mimeType, TEXT("text/plain")));
477 SysFreeString(mimeType);
481 BSTR resultString = 0;
484 if (::layoutTestController->dumpAsText()) {
485 ::InvalidateRect(webViewWindow, 0, TRUE);
486 ::SendMessage(webViewWindow, WM_PAINT, 0, 0);
487 wstring result = dumpFramesAsText(frame);
488 resultString = SysAllocStringLen(result.data(), result.size());
490 bool isSVGW3CTest = strstr(currentTest, "svg\\W3C-SVG-1.1");
497 width = maxViewWidth;
498 height = maxViewHeight;
501 ::SetWindowPos(webViewWindow, 0, 0, 0, width, height, SWP_NOMOVE);
502 ::InvalidateRect(webViewWindow, 0, TRUE);
503 ::SendMessage(webViewWindow, WM_PAINT, 0, 0);
505 COMPtr<IWebFramePrivate> framePrivate;
506 if (FAILED(frame->QueryInterface(&framePrivate)))
508 framePrivate->renderTreeAsExternalRepresentation(&resultString);
512 printf("ERROR: nil result from %s", ::layoutTestController->dumpAsText() ? "IDOMElement::innerText" : "IFrameViewPrivate::renderTreeAsExternalRepresentation");
514 unsigned stringLength = SysStringLen(resultString);
515 int bufferSize = ::WideCharToMultiByte(CP_UTF8, 0, resultString, stringLength, 0, 0, 0, 0);
516 char* buffer = (char*)malloc(bufferSize + 1);
517 int result = ::WideCharToMultiByte(CP_UTF8, 0, resultString, stringLength, buffer, bufferSize + 1, 0, 0);
518 buffer[bufferSize] = '\0';
519 printf("%s", buffer);
521 if (!::layoutTestController->dumpAsText())
522 dumpFrameScrollPosition(frame);
524 if (::layoutTestController->dumpBackForwardList())
525 dumpBackForwardList(frame);
531 SysFreeString(resultString);
532 // This will exit from our message loop
537 static void runTest(const char* pathOrURL)
539 static BSTR methodBStr = SysAllocString(TEXT("GET"));
543 CFStringRef str = CFStringCreateWithCString(kCFAllocatorDefault, pathOrURL, kCFStringEncodingWindowsLatin1);
544 CFURLRef url = CFURLCreateWithString(kCFAllocatorDefault, str, 0);
547 url = CFURLCreateWithFileSystemPath(kCFAllocatorDefault, str, kCFURLWindowsPathStyle, false);
551 str = CFURLGetString(url);
553 CFIndex length = CFStringGetLength(str);
554 UniChar* buffer = new UniChar[length];
556 CFStringGetCharacters(str, CFRangeMake(0, length), buffer);
557 urlBStr = SysAllocStringLen((OLECHAR*)buffer, length);
562 currentTest = pathOrURL;
564 ::layoutTestController = new LayoutTestController(false, false);
570 COMPtr<IWebView> webView;
571 if (SUCCEEDED(frame->webView(&webView))) {
572 COMPtr<IWebBackForwardList> bfList;
573 if (SUCCEEDED(webView->backForwardList(&bfList)))
574 bfList->currentItem(&prevTestBFItem);
576 COMPtr<IWebIBActions> webIBActions;
577 if (SUCCEEDED(webView->QueryInterface(IID_IWebIBActions, (void**)&webIBActions)))
578 webIBActions->makeTextStandardSize(0);
581 WorkQueue::shared()->clear();
582 WorkQueue::shared()->setFrozen(false);
584 // Set the test timeout timer
585 SetTimer(hostWindow, timeoutId, timeoutValue, 0);
587 COMPtr<IWebMutableURLRequest> request;
588 HRESULT hr = CoCreateInstance(CLSID_WebMutableURLRequest, 0, CLSCTX_ALL, IID_IWebMutableURLRequest, (void**)&request);
592 request->initWithURL(urlBStr, WebURLRequestUseProtocolCachePolicy, 0);
594 request->setHTTPMethod(methodBStr);
595 frame->loadRequest(request.get());
598 while (GetMessage(&msg, 0, 0, 0)) {
599 TranslateMessage(&msg);
600 DispatchMessage(&msg);
602 KillTimer(hostWindow, timeoutId);
605 fprintf(stderr, "ERROR: Timed out running %s\n", pathOrURL);
606 printf("ERROR: Timed out loading page\n");
612 SysFreeString(urlBStr);
616 static void initializePreferences(IWebPreferences* preferences)
619 BSTR standardFamily = SysAllocString(TEXT("Times"));
620 BSTR fixedFamily = SysAllocString(TEXT("Courier"));
621 BSTR sansSerifFamily = SysAllocString(TEXT("Helvetica"));
622 BSTR cursiveFamily = SysAllocString(TEXT("Apple Chancery"));
623 BSTR fantasyFamily = SysAllocString(TEXT("Papyrus"));
625 BSTR standardFamily = SysAllocString(TEXT("Times New Roman"));
626 BSTR fixedFamily = SysAllocString(TEXT("Courier New"));
627 BSTR sansSerifFamily = SysAllocString(TEXT("Arial"));
628 BSTR cursiveFamily = SysAllocString(TEXT("Comic Sans MS")); // Not actually cursive, but it's what IE and Firefox use.
629 BSTR fantasyFamily = SysAllocString(TEXT("Times New Roman"));
632 preferences->setStandardFontFamily(standardFamily);
633 preferences->setFixedFontFamily(fixedFamily);
634 preferences->setSerifFontFamily(standardFamily);
635 preferences->setSansSerifFontFamily(sansSerifFamily);
636 preferences->setCursiveFontFamily(cursiveFamily);
637 preferences->setFantasyFontFamily(fantasyFamily);
639 preferences->setAutosaves(FALSE);
640 preferences->setJavaEnabled(FALSE);
641 preferences->setPlugInsEnabled(TRUE);
642 preferences->setDOMPasteAllowed(TRUE);
643 preferences->setEditableLinkBehavior(WebKitEditableLinkOnlyLiveWithShiftKey);
645 SysFreeString(standardFamily);
646 SysFreeString(fixedFamily);
647 SysFreeString(sansSerifFamily);
648 SysFreeString(cursiveFamily);
649 SysFreeString(fantasyFamily);
652 static Boolean pthreadEqualCallback(const void* value1, const void* value2)
654 return (Boolean)pthread_equal(*(pthread_t*)value1, *(pthread_t*)value2);
657 static CFDictionaryKeyCallBacks pthreadKeyCallbacks = { 0, 0, 0, 0, pthreadEqualCallback, 0 };
659 static pthread_mutex_t javaScriptThreadsMutex = PTHREAD_MUTEX_INITIALIZER;
660 static bool javaScriptThreadsShouldTerminate;
662 static const int javaScriptThreadsCount = 4;
663 static CFMutableDictionaryRef javaScriptThreads()
665 assert(pthread_mutex_trylock(&javaScriptThreadsMutex) == EBUSY);
666 static CFMutableDictionaryRef staticJavaScriptThreads;
667 if (!staticJavaScriptThreads)
668 staticJavaScriptThreads = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &pthreadKeyCallbacks, 0);
669 return staticJavaScriptThreads;
672 // Loops forever, running a script and randomly respawning, until
673 // javaScriptThreadsShouldTerminate becomes true.
674 void* runJavaScriptThread(void* arg)
676 const char* const script =
679 for (var i = 0; i < 10; i++) { \
680 array.push(String(i)); \
685 JSGlobalContextRef ctx = JSGlobalContextCreate(0);
686 JSStringRef scriptRef = JSStringCreateWithUTF8CString(script);
688 JSValueRef exception = 0;
689 JSEvaluateScript(ctx, scriptRef, 0, 0, 0, &exception);
692 JSGlobalContextRelease(ctx);
693 JSStringRelease(scriptRef);
695 JSGarbageCollect(ctx);
697 pthread_mutex_lock(&javaScriptThreadsMutex);
699 // Check for cancellation.
700 if (javaScriptThreadsShouldTerminate) {
701 pthread_mutex_unlock(&javaScriptThreadsMutex);
705 // Respawn probabilistically.
706 if (rand() % 5 == 0) {
708 pthread_create(&pthread, 0, &runJavaScriptThread, 0);
709 pthread_detach(pthread);
711 pthread_t self = pthread_self();
712 CFDictionaryRemoveValue(javaScriptThreads(), self.p);
713 CFDictionaryAddValue(javaScriptThreads(), pthread.p, 0);
715 pthread_mutex_unlock(&javaScriptThreadsMutex);
719 pthread_mutex_unlock(&javaScriptThreadsMutex);
723 static void startJavaScriptThreads(void)
725 pthread_mutex_lock(&javaScriptThreadsMutex);
727 for (int i = 0; i < javaScriptThreadsCount; i++) {
729 pthread_create(&pthread, 0, &runJavaScriptThread, 0);
730 pthread_detach(pthread);
731 CFDictionaryAddValue(javaScriptThreads(), pthread.p, 0);
734 pthread_mutex_unlock(&javaScriptThreadsMutex);
737 static void stopJavaScriptThreads(void)
739 pthread_mutex_lock(&javaScriptThreadsMutex);
741 javaScriptThreadsShouldTerminate = true;
743 pthread_t* pthreads[javaScriptThreadsCount] = {0};
744 int threadDictCount = CFDictionaryGetCount(javaScriptThreads());
745 assert(threadDictCount == javaScriptThreadsCount);
746 CFDictionaryGetKeysAndValues(javaScriptThreads(), (const void**)pthreads, 0);
748 pthread_mutex_unlock(&javaScriptThreadsMutex);
750 for (int i = 0; i < javaScriptThreadsCount; i++) {
751 pthread_t* pthread = pthreads[i];
752 pthread_join(*pthread, 0);
757 int main(int argc, char* argv[])
759 leakChecking = false;
761 wstring exePath = initialize(GetModuleHandle(0));
765 COMPtr<IWebView> webView;
766 HRESULT hr = CoCreateInstance(CLSID_WebView, 0, CLSCTX_ALL, IID_IWebView, (void**)&webView);
768 fprintf(stderr, "Failed to create CLSID_WebView instance, error 0x%x\n", hr);
772 if (FAILED(webView->setHostWindow((OLE_HANDLE)(ULONG64)hostWindow)))
776 clientRect.bottom = clientRect.left = clientRect.top = clientRect.right = 0;
777 BSTR groupName = SysAllocString(L"org.webkit.DumpRenderTree");
778 bool failed = FAILED(webView->initWithFrame(clientRect, 0, groupName));
779 SysFreeString(groupName);
783 COMPtr<IWebViewPrivate> viewPrivate;
784 if (FAILED(webView->QueryInterface(&viewPrivate)))
789 BSTR pluginPath = SysAllocStringLen(0, exePath.length() + _tcslen(TestPluginDir));
790 _tcscpy(pluginPath, exePath.c_str());
791 _tcscat(pluginPath, TestPluginDir);
792 failed = FAILED(viewPrivate->addAdditionalPluginPath(pluginPath));
793 SysFreeString(pluginPath);
797 if (FAILED(viewPrivate->viewWindow((OLE_HANDLE*)&webViewWindow)))
800 SetWindowPos(webViewWindow, 0, 0, 0, maxViewWidth, maxViewHeight, 0);
801 ShowWindow(hostWindow, SW_SHOW);
803 COMPtr<FrameLoadDelegate> frameLoadDelegate;
804 frameLoadDelegate.adoptRef(new FrameLoadDelegate);
805 if (FAILED(webView->setFrameLoadDelegate(frameLoadDelegate.get())))
808 COMPtr<UIDelegate> uiDelegate;
809 uiDelegate.adoptRef(new UIDelegate);
810 if (FAILED(webView->setUIDelegate(uiDelegate.get())))
813 COMPtr<IWebViewEditing> viewEditing;
814 if (FAILED(webView->QueryInterface(&viewEditing)))
818 COMPtr<EditingDelegate> editingDelegate;
819 editingDelegate.adoptRef(new EditingDelegate);
820 if (FAILED(viewEditing->setEditingDelegate(editingDelegate.get())))
823 COMPtr<IWebPreferences> preferences;
824 if (FAILED(webView->preferences(&preferences)))
827 initializePreferences(preferences.get());
829 COMPtr<IWebIconDatabase> iconDatabase;
830 COMPtr<IWebIconDatabase> tmpIconDatabase;
831 if (FAILED(CoCreateInstance(CLSID_WebIconDatabase, 0, CLSCTX_ALL, IID_IWebIconDatabase, (void**)&tmpIconDatabase)))
833 if (FAILED(tmpIconDatabase->sharedIconDatabase(&iconDatabase)))
836 if (FAILED(webView->mainFrame(&frame)))
839 _CrtMemState entryToMainMemCheckpoint;
841 _CrtMemCheckpoint(&entryToMainMemCheckpoint);
843 for (int i = 0; i < argc; ++i)
844 if (!stricmp(argv[i], "--threaded")) {
845 argv[i] = argv[argc - 1];
852 startJavaScriptThreads();
854 if (argc == 2 && strcmp(argv[1], "-") == 0) {
855 char filenameBuffer[2048];
856 printSeparators = true;
857 while (fgets(filenameBuffer, sizeof(filenameBuffer), stdin)) {
858 char* newLineCharacter = strchr(filenameBuffer, '\n');
859 if (newLineCharacter)
860 *newLineCharacter = '\0';
862 if (strlen(filenameBuffer) == 0)
865 runTest(filenameBuffer);
869 printSeparators = argc > 2;
870 for (int i = 1; i != argc; i++)
875 stopJavaScriptThreads();
880 // dump leaks to stderr
881 _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE);
882 _CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDERR);
883 _CrtMemDumpAllObjectsSince(&entryToMainMemCheckpoint);