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 <WebKit/DOMPrivate.h>
46 #include <WebKit/IWebFramePrivate.h>
47 #include <WebKit/IWebHistoryItem.h>
48 #include <WebKit/IWebHistoryItemPrivate.h>
49 #include <WebKit/IWebURLResponse.h>
50 #include <WebKit/IWebViewPrivate.h>
51 #include <WebKit/WebKit.h>
58 const LPWSTR TestPluginDir = L"TestNetscapePlugin_Debug";
60 const LPWSTR TestPluginDir = L"TestNetscapePlugin";
65 const LPCWSTR kDumpRenderTreeClassName = L"DumpRenderTreeWindow";
67 static bool dumpTree = true;
68 static bool printSeparators;
69 static bool leakChecking = false;
70 static bool timedOut = false;
71 static bool threaded = false;
73 static const char* currentTest;
76 // This is the topmost frame that is loading, during a given load, or nil when no load is
77 // in progress. Usually this is the same as the main frame, but not always. In the case
78 // where a frameset is loaded, and then new content is loaded into one of the child frames,
79 // that child frame is the "topmost frame that is loading".
80 IWebFrame* topLoadingFrame; // !nil iff a load is in progress
81 static COMPtr<IWebHistoryItem> prevTestBFItem; // current b/f item at the end of the previous test
85 static HWND hostWindow;
87 LayoutTestController* layoutTestController = 0;
88 CFRunLoopTimerRef waitToDumpWatchdog = 0;
90 static const unsigned timeoutValue = 60000;
91 static const unsigned timeoutId = 10;
93 const unsigned maxViewWidth = 800;
94 const unsigned maxViewHeight = 600;
96 static LRESULT CALLBACK DumpRenderTreeWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
100 // The test ran long enough to time out
106 return DefWindowProc(hWnd, msg, wParam, lParam);
110 extern "C" BOOL InitializeCoreGraphics();
112 static wstring initialize(HMODULE hModule)
115 HMODULE webKitModule = LoadLibraryW(L"WebKit.dll");
117 HMODULE webKitModule = LoadLibraryW(L"WebKit_debug.dll");
119 FARPROC dllRegisterServer = ::GetProcAddress(webKitModule, "DllRegisterServer");
122 static LPCTSTR fontsToInstall[] = {
123 TEXT("AHEM____.ttf"),
124 TEXT("Apple Chancery.ttf"),
125 TEXT("Courier Bold.ttf"),
127 TEXT("Helvetica Bold.ttf"),
128 TEXT("Helvetica.ttf"),
129 TEXT("Helvetica Neue Bold Italic.ttf"),
130 TEXT("Helvetica Neue Bold.ttf"),
131 TEXT("Helvetica Neue Condensed Black.ttf"),
132 TEXT("Helvetica Neue Condensed Bold.ttf"),
133 TEXT("Helvetica Neue Italic.ttf"),
134 TEXT("Helvetica Neue Light Italic.ttf"),
135 TEXT("Helvetica Neue Light.ttf"),
136 TEXT("Helvetica Neue UltraLight Italic.ttf"),
137 TEXT("Helvetica Neue UltraLight.ttf"),
138 TEXT("Helvetica Neue.ttf"),
139 TEXT("Lucida Grande.ttf"),
140 TEXT("Lucida Grande Bold.ttf"),
143 TEXT("Times Bold Italic.ttf"),
144 TEXT("Times Bold.ttf"),
145 TEXT("Times Italic.ttf"),
146 TEXT("Times Roman.ttf")
149 TCHAR buffer[MAX_PATH];
150 GetModuleFileName(hModule, buffer, ARRAYSIZE(buffer));
151 wstring exePath(buffer);
152 int lastSlash = exePath.rfind('\\');
153 if (lastSlash != -1 && lastSlash + 1< exePath.length())
154 exePath = exePath.substr(0, lastSlash + 1);
156 wstring resourcesPath(exePath + TEXT("DumpRenderTree.resources\\"));
158 for (int i = 0; i < ARRAYSIZE(fontsToInstall); ++i)
159 AddFontResourceEx(wstring(resourcesPath + fontsToInstall[i]).c_str(), FR_PRIVATE, 0);
165 InitializeCoreGraphics();
167 // Register a host window
170 wcex.cbSize = sizeof(WNDCLASSEX);
172 wcex.style = CS_HREDRAW | CS_VREDRAW;
173 wcex.lpfnWndProc = DumpRenderTreeWndProc;
176 wcex.hInstance = hModule;
178 wcex.hCursor = LoadCursor(0, IDC_ARROW);
179 wcex.hbrBackground = 0;
180 wcex.lpszMenuName = 0;
181 wcex.lpszClassName = kDumpRenderTreeClassName;
184 RegisterClassEx(&wcex);
186 hostWindow = CreateWindowEx(WS_EX_TOOLWINDOW, kDumpRenderTreeClassName, TEXT("DumpRenderTree"), WS_POPUP,
187 -maxViewWidth, -maxViewHeight, maxViewWidth, maxViewHeight, 0, 0, hModule, 0);
192 void displayWebView()
194 ::InvalidateRect(webViewWindow, 0, TRUE);
195 ::UpdateWindow(webViewWindow);
198 void dumpFrameScrollPosition(IWebFrame* frame)
203 COMPtr<IWebFramePrivate> framePrivate;
204 if (FAILED(frame->QueryInterface(&framePrivate)))
208 if (FAILED(framePrivate->scrollOffset(&scrollPosition)))
211 if (abs(scrollPosition.cx) > 0.00000001 || abs(scrollPosition.cy) > 0.00000001) {
212 COMPtr<IWebFrame> parent;
213 if (FAILED(frame->parentFrame(&parent)))
217 if (FAILED(frame->name(&name)))
219 printf("frame '%S' ", name ? name : L"");
222 printf("scrolled to %.f,%.f\n", (double)scrollPosition.cx, (double)scrollPosition.cy);
225 if (::layoutTestController->dumpChildFrameScrollPositions()) {
226 COMPtr<IEnumVARIANT> enumKids;
227 if (FAILED(frame->childFrames(&enumKids)))
231 while (enumKids->Next(1, &var, 0) == S_OK) {
232 ASSERT(V_VT(&var) == VT_UNKNOWN);
233 COMPtr<IWebFrame> framePtr;
234 V_UNKNOWN(&var)->QueryInterface(IID_IWebFrame, (void**)&framePtr);
235 dumpFrameScrollPosition(framePtr.get());
241 static wstring dumpFramesAsText(IWebFrame* frame)
246 COMPtr<IDOMDocument> document;
247 if (FAILED(frame->DOMDocument(&document)))
250 COMPtr<IDOMElement> documentElement;
251 if (FAILED(document->documentElement(&documentElement)))
256 // Add header for all but the main frame.
257 COMPtr<IWebFrame> parent;
258 if (FAILED(frame->parentFrame(&parent)))
262 if (FAILED(frame->name(&name)))
265 result.append(L"\n--------\nFrame: '");
266 result.append(name ? name : L"");
267 result.append(L"'\n--------\n");
273 COMPtr<IDOMElementPrivate> docPrivate;
274 if (SUCCEEDED(documentElement->QueryInterface(&docPrivate)))
275 docPrivate->innerText(&innerText);
277 result.append(innerText ? innerText : L"");
278 result.append(L"\n");
280 SysFreeString(innerText);
282 if (::layoutTestController->dumpChildFramesAsText()) {
283 COMPtr<IEnumVARIANT> enumKids;
284 if (FAILED(frame->childFrames(&enumKids)))
288 while (enumKids->Next(1, &var, 0) == S_OK) {
289 ASSERT(V_VT(&var) == VT_UNKNOWN);
290 COMPtr<IWebFrame> framePtr;
291 V_UNKNOWN(&var)->QueryInterface(IID_IWebFrame, (void**)&framePtr);
292 result.append(dumpFramesAsText(framePtr.get()));
300 static int compareHistoryItems(const void* item1, const void* item2)
302 COMPtr<IWebHistoryItemPrivate> itemA;
303 if (FAILED((*(COMPtr<IUnknown>*)item1)->QueryInterface(&itemA)))
306 COMPtr<IWebHistoryItemPrivate> itemB;
307 if (FAILED((*(COMPtr<IUnknown>*)item2)->QueryInterface(&itemB)))
311 if (FAILED(itemA->target(&targetA)))
315 if (FAILED(itemB->target(&targetB))) {
316 SysFreeString(targetA);
320 int result = wcsicmp(wstring(targetA, SysStringLen(targetA)).c_str(), wstring(targetB, SysStringLen(targetB)).c_str());
321 SysFreeString(targetA);
322 SysFreeString(targetB);
326 static void dumpHistoryItem(IWebHistoryItem* item, int indent, bool current)
335 for (int i = start; i < indent; i++)
339 if (FAILED(item->URLString(&url)))
341 printf("%S", url ? url : L"");
344 COMPtr<IWebHistoryItemPrivate> itemPrivate;
345 if (FAILED(item->QueryInterface(&itemPrivate)))
349 if (FAILED(itemPrivate->target(&target)))
351 if (SysStringLen(target))
352 printf(" (in frame \"%S\")", target);
353 SysFreeString(target);
354 BOOL isTargetItem = FALSE;
355 if (FAILED(itemPrivate->isTargetItem(&isTargetItem)))
358 printf(" **nav target**");
363 if (FAILED(itemPrivate->children(&kidsCount, &arrPtr)) || !kidsCount)
366 Vector<COMPtr<IUnknown> > kidsVector;
369 if (FAILED(::SafeArrayGetLBound(arrPtr, 1, &lowerBound)))
373 if (FAILED(::SafeArrayGetUBound(arrPtr, 1, &upperBound)))
376 LONG length = upperBound - lowerBound + 1;
379 ASSERT(length == kidsCount);
381 IUnknown** safeArrayData;
382 if (FAILED(::SafeArrayAccessData(arrPtr, (void**)&safeArrayData)))
385 for (int i = 0; i < length; ++i)
386 kidsVector.append(safeArrayData[i]);
387 ::SafeArrayUnaccessData(arrPtr);
389 // must sort to eliminate arbitrary result ordering which defeats reproducible testing
390 qsort(kidsVector.data(), kidsCount, sizeof(kidsVector[0]), compareHistoryItems);
392 for (unsigned i = 0; i < kidsCount; ++i) {
393 COMPtr<IWebHistoryItem> item;
394 kidsVector[i]->QueryInterface(&item);
395 dumpHistoryItem(item.get(), indent + 4, false);
399 if (arrPtr && SUCCEEDED(::SafeArrayUnlock(arrPtr)))
400 ::SafeArrayDestroy(arrPtr);
403 static void dumpBackForwardList(IWebFrame* frame)
407 printf("\n============== Back Forward List ==============\n");
408 COMPtr<IWebView> webView;
409 if (FAILED(frame->webView(&webView)))
412 COMPtr<IWebBackForwardList> bfList;
413 if (FAILED(webView->backForwardList(&bfList)))
416 // Print out all items in the list after prevTestBFItem, which was from the previous test
417 // Gather items from the end of the list, the print them out from oldest to newest
419 Vector<COMPtr<IUnknown> > itemsToPrint;
421 int forwardListCount;
422 if (FAILED(bfList->forwardListCount(&forwardListCount)))
425 for (int i = forwardListCount; i > 0; --i) {
426 COMPtr<IWebHistoryItem> item;
427 if (FAILED(bfList->itemAtIndex(i, &item)))
429 // something is wrong if the item from the last test is in the forward part of the b/f list
430 assert(item != prevTestBFItem);
431 COMPtr<IUnknown> itemUnknown;
432 item->QueryInterface(&itemUnknown);
433 itemsToPrint.append(itemUnknown);
436 COMPtr<IWebHistoryItem> currentItem;
437 if (FAILED(bfList->currentItem(¤tItem)))
440 assert(currentItem != prevTestBFItem);
441 COMPtr<IUnknown> currentItemUnknown;
442 currentItem->QueryInterface(¤tItemUnknown);
443 itemsToPrint.append(currentItemUnknown);
444 int currentItemIndex = itemsToPrint.size() - 1;
447 if (FAILED(bfList->backListCount(&backListCount)))
450 for (int i = -1; i >= -backListCount; --i) {
451 COMPtr<IWebHistoryItem> item;
452 if (FAILED(bfList->itemAtIndex(i, &item)))
454 if (item == prevTestBFItem)
456 COMPtr<IUnknown> itemUnknown;
457 item->QueryInterface(&itemUnknown);
458 itemsToPrint.append(itemUnknown);
461 for (int i = itemsToPrint.size() - 1; i >= 0; --i) {
462 COMPtr<IWebHistoryItem> historyItemToPrint;
463 itemsToPrint[i]->QueryInterface(&historyItemToPrint);
464 dumpHistoryItem(historyItemToPrint.get(), 8, i == currentItemIndex);
467 printf("===============================================\n");
472 COMPtr<IWebDataSource> dataSource;
473 if (SUCCEEDED(frame->dataSource(&dataSource))) {
474 COMPtr<IWebURLResponse> response;
475 if (SUCCEEDED(dataSource->response(&response)) && response) {
477 if (SUCCEEDED(response->MIMEType(&mimeType)))
478 ::layoutTestController->setDumpAsText(::layoutTestController->dumpAsText() | !_tcscmp(mimeType, TEXT("text/plain")));
479 SysFreeString(mimeType);
483 BSTR resultString = 0;
486 if (::layoutTestController->dumpAsText()) {
487 ::InvalidateRect(webViewWindow, 0, TRUE);
488 ::SendMessage(webViewWindow, WM_PAINT, 0, 0);
489 wstring result = dumpFramesAsText(frame);
490 resultString = SysAllocStringLen(result.data(), result.size());
492 bool isSVGW3CTest = strstr(currentTest, "svg\\W3C-SVG-1.1");
499 width = maxViewWidth;
500 height = maxViewHeight;
503 ::SetWindowPos(webViewWindow, 0, 0, 0, width, height, SWP_NOMOVE);
504 ::InvalidateRect(webViewWindow, 0, TRUE);
505 ::SendMessage(webViewWindow, WM_PAINT, 0, 0);
507 COMPtr<IWebFramePrivate> framePrivate;
508 if (FAILED(frame->QueryInterface(&framePrivate)))
510 framePrivate->renderTreeAsExternalRepresentation(&resultString);
514 printf("ERROR: nil result from %s", ::layoutTestController->dumpAsText() ? "IDOMElement::innerText" : "IFrameViewPrivate::renderTreeAsExternalRepresentation");
516 unsigned stringLength = SysStringLen(resultString);
517 int bufferSize = ::WideCharToMultiByte(CP_UTF8, 0, resultString, stringLength, 0, 0, 0, 0);
518 char* buffer = (char*)malloc(bufferSize + 1);
519 int result = ::WideCharToMultiByte(CP_UTF8, 0, resultString, stringLength, buffer, bufferSize + 1, 0, 0);
520 buffer[bufferSize] = '\0';
521 printf("%s", buffer);
523 if (!::layoutTestController->dumpAsText())
524 dumpFrameScrollPosition(frame);
526 if (::layoutTestController->dumpBackForwardList())
527 dumpBackForwardList(frame);
533 SysFreeString(resultString);
534 // This will exit from our message loop
539 static void runTest(const char* pathOrURL)
541 static BSTR methodBStr = SysAllocString(TEXT("GET"));
545 CFStringRef str = CFStringCreateWithCString(kCFAllocatorDefault, pathOrURL, kCFStringEncodingWindowsLatin1);
546 CFURLRef url = CFURLCreateWithString(kCFAllocatorDefault, str, 0);
549 url = CFURLCreateWithFileSystemPath(kCFAllocatorDefault, str, kCFURLWindowsPathStyle, false);
553 str = CFURLGetString(url);
555 CFIndex length = CFStringGetLength(str);
556 UniChar* buffer = new UniChar[length];
558 CFStringGetCharacters(str, CFRangeMake(0, length), buffer);
559 urlBStr = SysAllocStringLen((OLECHAR*)buffer, length);
564 currentTest = pathOrURL;
566 ::layoutTestController = new LayoutTestController(false, false);
572 COMPtr<IWebView> webView;
573 if (SUCCEEDED(frame->webView(&webView))) {
574 COMPtr<IWebBackForwardList> bfList;
575 if (SUCCEEDED(webView->backForwardList(&bfList)))
576 bfList->currentItem(&prevTestBFItem);
578 COMPtr<IWebIBActions> webIBActions;
579 if (SUCCEEDED(webView->QueryInterface(IID_IWebIBActions, (void**)&webIBActions)))
580 webIBActions->makeTextStandardSize(0);
583 WorkQueue::shared()->clear();
584 WorkQueue::shared()->setFrozen(false);
586 // Set the test timeout timer
587 SetTimer(hostWindow, timeoutId, timeoutValue, 0);
589 COMPtr<IWebMutableURLRequest> request;
590 HRESULT hr = CoCreateInstance(CLSID_WebMutableURLRequest, 0, CLSCTX_ALL, IID_IWebMutableURLRequest, (void**)&request);
594 request->initWithURL(urlBStr, WebURLRequestUseProtocolCachePolicy, 0);
596 request->setHTTPMethod(methodBStr);
597 frame->loadRequest(request.get());
600 while (GetMessage(&msg, 0, 0, 0)) {
601 TranslateMessage(&msg);
602 DispatchMessage(&msg);
604 KillTimer(hostWindow, timeoutId);
607 fprintf(stderr, "ERROR: Timed out running %s\n", pathOrURL);
608 printf("ERROR: Timed out loading page\n");
614 SysFreeString(urlBStr);
618 static void initializePreferences(IWebPreferences* preferences)
621 BSTR standardFamily = SysAllocString(TEXT("Times"));
622 BSTR fixedFamily = SysAllocString(TEXT("Courier"));
623 BSTR sansSerifFamily = SysAllocString(TEXT("Helvetica"));
624 BSTR cursiveFamily = SysAllocString(TEXT("Apple Chancery"));
625 BSTR fantasyFamily = SysAllocString(TEXT("Papyrus"));
627 BSTR standardFamily = SysAllocString(TEXT("Times New Roman"));
628 BSTR fixedFamily = SysAllocString(TEXT("Courier New"));
629 BSTR sansSerifFamily = SysAllocString(TEXT("Arial"));
630 BSTR cursiveFamily = SysAllocString(TEXT("Comic Sans MS")); // Not actually cursive, but it's what IE and Firefox use.
631 BSTR fantasyFamily = SysAllocString(TEXT("Times New Roman"));
634 preferences->setStandardFontFamily(standardFamily);
635 preferences->setFixedFontFamily(fixedFamily);
636 preferences->setSerifFontFamily(standardFamily);
637 preferences->setSansSerifFontFamily(sansSerifFamily);
638 preferences->setCursiveFontFamily(cursiveFamily);
639 preferences->setFantasyFontFamily(fantasyFamily);
641 preferences->setAutosaves(FALSE);
642 preferences->setJavaEnabled(FALSE);
643 preferences->setPlugInsEnabled(TRUE);
644 preferences->setDOMPasteAllowed(TRUE);
645 preferences->setEditableLinkBehavior(WebKitEditableLinkOnlyLiveWithShiftKey);
647 SysFreeString(standardFamily);
648 SysFreeString(fixedFamily);
649 SysFreeString(sansSerifFamily);
650 SysFreeString(cursiveFamily);
651 SysFreeString(fantasyFamily);
654 static Boolean pthreadEqualCallback(const void* value1, const void* value2)
656 return (Boolean)pthread_equal(*(pthread_t*)value1, *(pthread_t*)value2);
659 static CFDictionaryKeyCallBacks pthreadKeyCallbacks = { 0, 0, 0, 0, pthreadEqualCallback, 0 };
661 static pthread_mutex_t javaScriptThreadsMutex = PTHREAD_MUTEX_INITIALIZER;
662 static bool javaScriptThreadsShouldTerminate;
664 static const int javaScriptThreadsCount = 4;
665 static CFMutableDictionaryRef javaScriptThreads()
667 assert(pthread_mutex_trylock(&javaScriptThreadsMutex) == EBUSY);
668 static CFMutableDictionaryRef staticJavaScriptThreads;
669 if (!staticJavaScriptThreads)
670 staticJavaScriptThreads = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &pthreadKeyCallbacks, 0);
671 return staticJavaScriptThreads;
674 // Loops forever, running a script and randomly respawning, until
675 // javaScriptThreadsShouldTerminate becomes true.
676 void* runJavaScriptThread(void* arg)
678 const char* const script =
681 for (var i = 0; i < 10; i++) { \
682 array.push(String(i)); \
687 JSGlobalContextRef ctx = JSGlobalContextCreate(0);
688 JSStringRef scriptRef = JSStringCreateWithUTF8CString(script);
690 JSValueRef exception = 0;
691 JSEvaluateScript(ctx, scriptRef, 0, 0, 0, &exception);
694 JSGlobalContextRelease(ctx);
695 JSStringRelease(scriptRef);
697 JSGarbageCollect(ctx);
699 pthread_mutex_lock(&javaScriptThreadsMutex);
701 // Check for cancellation.
702 if (javaScriptThreadsShouldTerminate) {
703 pthread_mutex_unlock(&javaScriptThreadsMutex);
707 // Respawn probabilistically.
708 if (rand() % 5 == 0) {
710 pthread_create(&pthread, 0, &runJavaScriptThread, 0);
711 pthread_detach(pthread);
713 pthread_t self = pthread_self();
714 CFDictionaryRemoveValue(javaScriptThreads(), self.p);
715 CFDictionaryAddValue(javaScriptThreads(), pthread.p, 0);
717 pthread_mutex_unlock(&javaScriptThreadsMutex);
721 pthread_mutex_unlock(&javaScriptThreadsMutex);
725 static void startJavaScriptThreads(void)
727 pthread_mutex_lock(&javaScriptThreadsMutex);
729 for (int i = 0; i < javaScriptThreadsCount; i++) {
731 pthread_create(&pthread, 0, &runJavaScriptThread, 0);
732 pthread_detach(pthread);
733 CFDictionaryAddValue(javaScriptThreads(), pthread.p, 0);
736 pthread_mutex_unlock(&javaScriptThreadsMutex);
739 static void stopJavaScriptThreads(void)
741 pthread_mutex_lock(&javaScriptThreadsMutex);
743 javaScriptThreadsShouldTerminate = true;
745 pthread_t* pthreads[javaScriptThreadsCount] = {0};
746 int threadDictCount = CFDictionaryGetCount(javaScriptThreads());
747 assert(threadDictCount == javaScriptThreadsCount);
748 CFDictionaryGetKeysAndValues(javaScriptThreads(), (const void**)pthreads, 0);
750 pthread_mutex_unlock(&javaScriptThreadsMutex);
752 for (int i = 0; i < javaScriptThreadsCount; i++) {
753 pthread_t* pthread = pthreads[i];
754 pthread_join(*pthread, 0);
759 int main(int argc, char* argv[])
761 leakChecking = false;
763 wstring exePath = initialize(GetModuleHandle(0));
767 COMPtr<IWebView> webView;
768 HRESULT hr = CoCreateInstance(CLSID_WebView, 0, CLSCTX_ALL, IID_IWebView, (void**)&webView);
770 fprintf(stderr, "Failed to create CLSID_WebView instance, error 0x%x\n", hr);
774 if (FAILED(webView->setHostWindow((OLE_HANDLE)(ULONG64)hostWindow)))
778 clientRect.bottom = clientRect.left = clientRect.top = clientRect.right = 0;
779 BSTR groupName = SysAllocString(L"org.webkit.DumpRenderTree");
780 bool failed = FAILED(webView->initWithFrame(clientRect, 0, groupName));
781 SysFreeString(groupName);
785 COMPtr<IWebViewPrivate> viewPrivate;
786 if (FAILED(webView->QueryInterface(&viewPrivate)))
791 BSTR pluginPath = SysAllocStringLen(0, exePath.length() + _tcslen(TestPluginDir));
792 _tcscpy(pluginPath, exePath.c_str());
793 _tcscat(pluginPath, TestPluginDir);
794 failed = FAILED(viewPrivate->addAdditionalPluginPath(pluginPath));
795 SysFreeString(pluginPath);
799 if (FAILED(viewPrivate->viewWindow((OLE_HANDLE*)&webViewWindow)))
802 SetWindowPos(webViewWindow, 0, 0, 0, maxViewWidth, maxViewHeight, 0);
803 ShowWindow(hostWindow, SW_SHOW);
805 COMPtr<FrameLoadDelegate> frameLoadDelegate;
806 frameLoadDelegate.adoptRef(new FrameLoadDelegate);
807 if (FAILED(webView->setFrameLoadDelegate(frameLoadDelegate.get())))
810 COMPtr<UIDelegate> uiDelegate;
811 uiDelegate.adoptRef(new UIDelegate);
812 if (FAILED(webView->setUIDelegate(uiDelegate.get())))
815 COMPtr<IWebViewEditing> viewEditing;
816 if (FAILED(webView->QueryInterface(&viewEditing)))
820 COMPtr<EditingDelegate> editingDelegate;
821 editingDelegate.adoptRef(new EditingDelegate);
822 if (FAILED(viewEditing->setEditingDelegate(editingDelegate.get())))
825 COMPtr<IWebPreferences> preferences;
826 if (FAILED(webView->preferences(&preferences)))
829 initializePreferences(preferences.get());
831 COMPtr<IWebIconDatabase> iconDatabase;
832 COMPtr<IWebIconDatabase> tmpIconDatabase;
833 if (FAILED(CoCreateInstance(CLSID_WebIconDatabase, 0, CLSCTX_ALL, IID_IWebIconDatabase, (void**)&tmpIconDatabase)))
835 if (FAILED(tmpIconDatabase->sharedIconDatabase(&iconDatabase)))
838 if (FAILED(webView->mainFrame(&frame)))
841 _CrtMemState entryToMainMemCheckpoint;
843 _CrtMemCheckpoint(&entryToMainMemCheckpoint);
845 for (int i = 0; i < argc; ++i)
846 if (!stricmp(argv[i], "--threaded")) {
847 argv[i] = argv[argc - 1];
854 startJavaScriptThreads();
856 if (argc == 2 && strcmp(argv[1], "-") == 0) {
857 char filenameBuffer[2048];
858 printSeparators = true;
859 while (fgets(filenameBuffer, sizeof(filenameBuffer), stdin)) {
860 char* newLineCharacter = strchr(filenameBuffer, '\n');
861 if (newLineCharacter)
862 *newLineCharacter = '\0';
864 if (strlen(filenameBuffer) == 0)
867 runTest(filenameBuffer);
871 printSeparators = argc > 2;
872 for (int i = 1; i != argc; i++)
877 stopJavaScriptThreads();
882 // dump leaks to stderr
883 _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE);
884 _CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDERR);
885 _CrtMemDumpAllObjectsSince(&entryToMainMemCheckpoint);