2 * Copyright (C) 2005, 2006, 2007, 2008, 2009 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.
30 #include "DumpRenderTree.h"
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"
52 #include <wtf/RetainPtr.h>
53 #include <wtf/Vector.h>
55 #include <CoreFoundation/CoreFoundation.h>
56 #include <JavaScriptCore/JavaScriptCore.h>
57 #include <WebKit/WebKit.h>
58 #include <WebKit/WebKitCOMAPI.h>
61 #include <CFNetwork/CFURLCachePriv.h>
65 #include <CFNetwork/CFHTTPCookiesPriv.h>
71 const LPWSTR TestPluginDir = L"TestNetscapePlugin_Debug";
73 const LPWSTR TestPluginDir = L"TestNetscapePlugin";
76 static LPCWSTR fontsEnvironmentVariable = L"WEBKIT_TESTFONTS";
79 const LPCWSTR kDumpRenderTreeClassName = L"DumpRenderTreeWindow";
81 static bool dumpTree = true;
82 static bool dumpPixels;
83 static bool dumpAllPixels;
84 static bool printSeparators;
85 static bool leakChecking = false;
86 static bool threaded = false;
87 static bool forceComplexText = false;
88 static bool printSupportedFeatures = false;
89 static RetainPtr<CFStringRef> persistentUserStyleSheetLocation;
92 // This is the topmost frame that is loading, during a given load, or nil when no load is
93 // in progress. Usually this is the same as the main frame, but not always. In the case
94 // where a frameset is loaded, and then new content is loaded into one of the child frames,
95 // that child frame is the "topmost frame that is loading".
96 IWebFrame* topLoadingFrame; // !nil iff a load is in progress
97 static COMPtr<IWebHistoryItem> prevTestBFItem; // current b/f item at the end of the previous test
98 PolicyDelegate* policyDelegate;
99 COMPtr<FrameLoadDelegate> sharedFrameLoadDelegate;
100 COMPtr<UIDelegate> sharedUIDelegate;
101 COMPtr<EditingDelegate> sharedEditingDelegate;
102 COMPtr<HistoryDelegate> sharedHistoryDelegate;
107 RefPtr<LayoutTestController> gLayoutTestController;
109 UINT_PTR waitToDumpWatchdog = 0;
111 void setPersistentUserStyleSheetLocation(CFStringRef url)
113 persistentUserStyleSheetLocation = url;
116 bool setAlwaysAcceptCookies(bool alwaysAcceptCookies)
119 COMPtr<IWebCookieManager> cookieManager;
120 if (FAILED(WebKitCreateInstance(CLSID_WebCookieManager, 0, IID_IWebCookieManager, reinterpret_cast<void**>(&cookieManager))))
122 CFHTTPCookieStorageRef cookieStorage = 0;
123 if (FAILED(cookieManager->cookieStorage(&cookieStorage)) || !cookieStorage)
126 WebKitCookieStorageAcceptPolicy cookieAcceptPolicy = alwaysAcceptCookies ? WebKitCookieStorageAcceptPolicyAlways : WebKitCookieStorageAcceptPolicyOnlyFromMainDocumentDomain;
127 CFHTTPCookieStorageSetCookieAcceptPolicy(cookieStorage, cookieAcceptPolicy);
135 static RetainPtr<CFStringRef> substringFromIndex(CFStringRef string, CFIndex index)
137 return RetainPtr<CFStringRef>(AdoptCF, CFStringCreateWithSubstring(kCFAllocatorDefault, string, CFRangeMake(index, CFStringGetLength(string) - index)));
140 wstring urlSuitableForTestResult(const wstring& urlString)
142 RetainPtr<CFURLRef> url(AdoptCF, CFURLCreateWithBytes(kCFAllocatorDefault, reinterpret_cast<const UInt8*>(urlString.c_str()), urlString.length() * sizeof(wstring::value_type), kCFStringEncodingUTF16, 0));
144 RetainPtr<CFStringRef> scheme(AdoptCF, CFURLCopyScheme(url.get()));
145 if (scheme && CFStringCompare(scheme.get(), CFSTR("file"), kCFCompareCaseInsensitive) != kCFCompareEqualTo)
148 COMPtr<IWebDataSource> dataSource;
149 if (FAILED(frame->dataSource(&dataSource))) {
150 if (FAILED(frame->provisionalDataSource(&dataSource)))
154 COMPtr<IWebMutableURLRequest> request;
155 if (FAILED(dataSource->request(&request)))
158 _bstr_t requestURLString;
159 if (FAILED(request->URL(requestURLString.GetAddress())))
162 RetainPtr<CFURLRef> requestURL(AdoptCF, CFURLCreateWithBytes(kCFAllocatorDefault, reinterpret_cast<const UInt8*>(requestURLString.GetBSTR()), requestURLString.length() * sizeof(OLECHAR), kCFStringEncodingUTF16, 0));
163 RetainPtr<CFURLRef> baseURL(AdoptCF, CFURLCreateCopyDeletingLastPathComponent(kCFAllocatorDefault, requestURL.get()));
165 RetainPtr<CFStringRef> basePath(AdoptCF, CFURLCopyPath(baseURL.get()));
166 RetainPtr<CFStringRef> path(AdoptCF, CFURLCopyPath(url.get()));
168 return cfStringRefToWString(substringFromIndex(path.get(), CFStringGetLength(basePath.get())).get());
171 wstring lastPathComponent(const wstring& urlString)
173 if (urlString.empty())
176 RetainPtr<CFURLRef> url(AdoptCF, CFURLCreateWithBytes(kCFAllocatorDefault, reinterpret_cast<const UInt8*>(urlString.c_str()), urlString.length() * sizeof(wstring::value_type), kCFStringEncodingUTF16, 0));
177 RetainPtr<CFStringRef> lastPathComponent(CFURLCopyLastPathComponent(url.get()));
179 return cfStringRefToWString(lastPathComponent.get());
182 static string toUTF8(const wchar_t* wideString, size_t length)
184 int result = WideCharToMultiByte(CP_UTF8, 0, wideString, length + 1, 0, 0, 0, 0);
185 Vector<char> utf8Vector(result);
186 result = WideCharToMultiByte(CP_UTF8, 0, wideString, length + 1, utf8Vector.data(), result, 0, 0);
190 return string(utf8Vector.data(), utf8Vector.size() - 1);
193 string toUTF8(BSTR bstr)
195 return toUTF8(bstr, SysStringLen(bstr));
198 string toUTF8(const wstring& wideString)
200 return toUTF8(wideString.c_str(), wideString.length());
203 wstring cfStringRefToWString(CFStringRef cfStr)
205 Vector<wchar_t> v(CFStringGetLength(cfStr));
206 CFStringGetCharacters(cfStr, CFRangeMake(0, CFStringGetLength(cfStr)), (UniChar *)v.data());
208 return wstring(v.data(), v.size());
211 static LRESULT CALLBACK DumpRenderTreeWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
215 for (unsigned i = openWindows().size() - 1; i >= 0; --i) {
216 if (openWindows()[i] == hWnd) {
217 openWindows().remove(i);
218 windowToWebViewMap().remove(hWnd);
225 return DefWindowProc(hWnd, msg, wParam, lParam);
229 static const wstring& exePath()
232 static bool initialized;
238 TCHAR buffer[MAX_PATH];
239 GetModuleFileName(GetModuleHandle(0), buffer, ARRAYSIZE(buffer));
241 int lastSlash = path.rfind('\\');
242 if (lastSlash != -1 && lastSlash + 1 < path.length())
243 path = path.substr(0, lastSlash + 1);
248 static const wstring& fontsPath()
251 static bool initialized;
257 DWORD size = GetEnvironmentVariable(fontsEnvironmentVariable, 0, 0);
258 Vector<TCHAR> buffer(size);
259 if (GetEnvironmentVariable(fontsEnvironmentVariable, buffer.data(), buffer.size())) {
260 path = buffer.data();
261 if (path[path.length() - 1] != '\\')
266 path = exePath() + TEXT("DumpRenderTree.resources\\");
270 static void addQTDirToPATH()
272 static LPCWSTR pathEnvironmentVariable = L"PATH";
273 static LPCWSTR quickTimeKeyName = L"Software\\Apple Computer, Inc.\\QuickTime";
274 static LPCWSTR quickTimeSysDir = L"QTSysDir";
275 static bool initialized;
281 // Get the QuickTime dll directory from the registry. The key can be in either HKLM or HKCU.
282 WCHAR qtPath[MAX_PATH];
283 DWORD qtPathBufferLen = sizeof(qtPath);
285 HRESULT result = SHGetValue(HKEY_LOCAL_MACHINE, quickTimeKeyName, quickTimeSysDir, &keyType, (LPVOID)qtPath, &qtPathBufferLen);
286 if (result != ERROR_SUCCESS || !qtPathBufferLen || keyType != REG_SZ) {
287 qtPathBufferLen = sizeof(qtPath);
288 result = SHGetValue(HKEY_CURRENT_USER, quickTimeKeyName, quickTimeSysDir, &keyType, (LPVOID)qtPath, &qtPathBufferLen);
289 if (result != ERROR_SUCCESS || !qtPathBufferLen || keyType != REG_SZ)
293 // Read the current PATH.
294 DWORD pathSize = GetEnvironmentVariableW(pathEnvironmentVariable, 0, 0);
295 Vector<WCHAR> oldPath(pathSize);
296 if (!GetEnvironmentVariableW(pathEnvironmentVariable, oldPath.data(), oldPath.size()))
299 // And add the QuickTime dll.
301 newPath.append(qtPath);
302 newPath.append(L";");
303 newPath.append(oldPath.data(), oldPath.size());
304 SetEnvironmentVariableW(pathEnvironmentVariable, newPath.data());
308 #define WEBKITDLL TEXT("WebKit_debug.dll")
310 #define WEBKITDLL TEXT("WebKit.dll")
313 static void initialize()
315 if (HMODULE webKitModule = LoadLibrary(WEBKITDLL))
316 if (FARPROC dllRegisterServer = GetProcAddress(webKitModule, "DllRegisterServer"))
322 static LPCTSTR fontsToInstall[] = {
323 TEXT("AHEM____.ttf"),
324 TEXT("Apple Chancery.ttf"),
325 TEXT("Courier Bold.ttf"),
327 TEXT("Helvetica Bold Oblique.ttf"),
328 TEXT("Helvetica Bold.ttf"),
329 TEXT("Helvetica Oblique.ttf"),
330 TEXT("Helvetica.ttf"),
331 TEXT("Helvetica Neue Bold Italic.ttf"),
332 TEXT("Helvetica Neue Bold.ttf"),
333 TEXT("Helvetica Neue Condensed Black.ttf"),
334 TEXT("Helvetica Neue Condensed Bold.ttf"),
335 TEXT("Helvetica Neue Italic.ttf"),
336 TEXT("Helvetica Neue Light Italic.ttf"),
337 TEXT("Helvetica Neue Light.ttf"),
338 TEXT("Helvetica Neue UltraLight Italic.ttf"),
339 TEXT("Helvetica Neue UltraLight.ttf"),
340 TEXT("Helvetica Neue.ttf"),
341 TEXT("Lucida Grande.ttf"),
342 TEXT("Lucida Grande Bold.ttf"),
345 TEXT("Times Bold Italic.ttf"),
346 TEXT("Times Bold.ttf"),
347 TEXT("Times Italic.ttf"),
348 TEXT("Times Roman.ttf"),
349 TEXT("WebKit Layout Tests 2.ttf"),
350 TEXT("WebKit Layout Tests.ttf"),
351 TEXT("WebKitWeightWatcher100.ttf"),
352 TEXT("WebKitWeightWatcher200.ttf"),
353 TEXT("WebKitWeightWatcher300.ttf"),
354 TEXT("WebKitWeightWatcher400.ttf"),
355 TEXT("WebKitWeightWatcher500.ttf"),
356 TEXT("WebKitWeightWatcher600.ttf"),
357 TEXT("WebKitWeightWatcher700.ttf"),
358 TEXT("WebKitWeightWatcher800.ttf"),
359 TEXT("WebKitWeightWatcher900.ttf")
362 wstring resourcesPath = fontsPath();
364 COMPtr<IWebTextRenderer> textRenderer;
365 if (SUCCEEDED(WebKitCreateInstance(CLSID_WebTextRenderer, 0, IID_IWebTextRenderer, (void**)&textRenderer)))
366 for (int i = 0; i < ARRAYSIZE(fontsToInstall); ++i)
367 textRenderer->registerPrivateFont(wstring(resourcesPath + fontsToInstall[i]).c_str());
369 // Add the QuickTime dll directory to PATH or QT 7.6 will fail to initialize on systems
370 // linked with older versions of qtmlclientlib.dll.
373 // Register a host window
376 wcex.cbSize = sizeof(WNDCLASSEX);
378 wcex.style = CS_HREDRAW | CS_VREDRAW;
379 wcex.lpfnWndProc = DumpRenderTreeWndProc;
382 wcex.hInstance = GetModuleHandle(0);
384 wcex.hCursor = LoadCursor(0, IDC_ARROW);
385 wcex.hbrBackground = 0;
386 wcex.lpszMenuName = 0;
387 wcex.lpszClassName = kDumpRenderTreeClassName;
390 RegisterClassEx(&wcex);
393 void displayWebView()
395 ::InvalidateRect(webViewWindow, 0, TRUE);
396 ::SendMessage(webViewWindow, WM_PAINT, 0, 0);
399 void dumpFrameScrollPosition(IWebFrame* frame)
404 COMPtr<IWebFramePrivate> framePrivate;
405 if (FAILED(frame->QueryInterface(&framePrivate)))
409 if (FAILED(framePrivate->scrollOffset(&scrollPosition)))
412 if (abs(scrollPosition.cx) > 0.00000001 || abs(scrollPosition.cy) > 0.00000001) {
413 COMPtr<IWebFrame> parent;
414 if (FAILED(frame->parentFrame(&parent)))
418 if (FAILED(frame->name(&name)))
420 printf("frame '%S' ", name ? name : L"");
423 printf("scrolled to %.f,%.f\n", (double)scrollPosition.cx, (double)scrollPosition.cy);
426 if (::gLayoutTestController->dumpChildFrameScrollPositions()) {
427 COMPtr<IEnumVARIANT> enumKids;
428 if (FAILED(frame->childFrames(&enumKids)))
432 while (enumKids->Next(1, &var, 0) == S_OK) {
433 ASSERT(V_VT(&var) == VT_UNKNOWN);
434 COMPtr<IWebFrame> framePtr;
435 V_UNKNOWN(&var)->QueryInterface(IID_IWebFrame, (void**)&framePtr);
436 dumpFrameScrollPosition(framePtr.get());
442 static wstring dumpFramesAsText(IWebFrame* frame)
447 COMPtr<IDOMDocument> document;
448 if (FAILED(frame->DOMDocument(&document)))
451 COMPtr<IDOMElement> documentElement;
452 if (FAILED(document->documentElement(&documentElement)))
457 // Add header for all but the main frame.
458 COMPtr<IWebFrame> parent;
459 if (FAILED(frame->parentFrame(&parent)))
463 if (FAILED(frame->name(&name)))
466 result.append(L"\n--------\nFrame: '");
467 result.append(name ? name : L"", SysStringLen(name));
468 result.append(L"'\n--------\n");
474 COMPtr<IDOMElementPrivate> docPrivate;
475 if (SUCCEEDED(documentElement->QueryInterface(&docPrivate)))
476 docPrivate->innerText(&innerText);
478 result.append(innerText ? innerText : L"", SysStringLen(innerText));
479 result.append(L"\n");
481 SysFreeString(innerText);
483 if (::gLayoutTestController->dumpChildFramesAsText()) {
484 COMPtr<IEnumVARIANT> enumKids;
485 if (FAILED(frame->childFrames(&enumKids)))
489 while (enumKids->Next(1, &var, 0) == S_OK) {
490 ASSERT(V_VT(&var) == VT_UNKNOWN);
491 COMPtr<IWebFrame> framePtr;
492 V_UNKNOWN(&var)->QueryInterface(IID_IWebFrame, (void**)&framePtr);
493 result.append(dumpFramesAsText(framePtr.get()));
501 static int compareHistoryItems(const void* item1, const void* item2)
503 COMPtr<IWebHistoryItemPrivate> itemA;
504 if (FAILED((*(COMPtr<IUnknown>*)item1)->QueryInterface(&itemA)))
507 COMPtr<IWebHistoryItemPrivate> itemB;
508 if (FAILED((*(COMPtr<IUnknown>*)item2)->QueryInterface(&itemB)))
512 if (FAILED(itemA->target(&targetA)))
516 if (FAILED(itemB->target(&targetB))) {
517 SysFreeString(targetA);
521 int result = wcsicmp(wstring(targetA, SysStringLen(targetA)).c_str(), wstring(targetB, SysStringLen(targetB)).c_str());
522 SysFreeString(targetA);
523 SysFreeString(targetB);
527 static void dumpHistoryItem(IWebHistoryItem* item, int indent, bool current)
536 for (int i = start; i < indent; i++)
540 if (FAILED(item->URLString(&url)))
543 if (wcsstr(url, L"file:/") == url) {
544 static wchar_t* layoutTestsString = L"/LayoutTests/";
545 static wchar_t* fileTestString = L"(file test):";
547 wchar_t* result = wcsstr(url, layoutTestsString);
550 wchar_t* start = result + wcslen(layoutTestsString);
552 BSTR newURL = SysAllocStringLen(NULL, SysStringLen(url));
553 wcscpy(newURL, fileTestString);
554 wcscpy(newURL + wcslen(fileTestString), start);
560 printf("%S", url ? url : L"");
563 COMPtr<IWebHistoryItemPrivate> itemPrivate;
564 if (FAILED(item->QueryInterface(&itemPrivate)))
568 if (FAILED(itemPrivate->target(&target)))
570 if (SysStringLen(target))
571 printf(" (in frame \"%S\")", target);
572 SysFreeString(target);
573 BOOL isTargetItem = FALSE;
574 if (FAILED(itemPrivate->isTargetItem(&isTargetItem)))
577 printf(" **nav target**");
582 if (FAILED(itemPrivate->children(&kidsCount, &arrPtr)) || !kidsCount)
585 Vector<COMPtr<IUnknown> > kidsVector;
588 if (FAILED(::SafeArrayGetLBound(arrPtr, 1, &lowerBound)))
592 if (FAILED(::SafeArrayGetUBound(arrPtr, 1, &upperBound)))
595 LONG length = upperBound - lowerBound + 1;
598 ASSERT(length == kidsCount);
600 IUnknown** safeArrayData;
601 if (FAILED(::SafeArrayAccessData(arrPtr, (void**)&safeArrayData)))
604 for (int i = 0; i < length; ++i)
605 kidsVector.append(safeArrayData[i]);
606 ::SafeArrayUnaccessData(arrPtr);
608 // must sort to eliminate arbitrary result ordering which defeats reproducible testing
609 qsort(kidsVector.data(), kidsCount, sizeof(kidsVector[0]), compareHistoryItems);
611 for (unsigned i = 0; i < kidsCount; ++i) {
612 COMPtr<IWebHistoryItem> item;
613 kidsVector[i]->QueryInterface(&item);
614 dumpHistoryItem(item.get(), indent + 4, false);
618 if (arrPtr && SUCCEEDED(::SafeArrayUnlock(arrPtr)))
619 ::SafeArrayDestroy(arrPtr);
622 static void dumpBackForwardList(IWebView* webView)
626 printf("\n============== Back Forward List ==============\n");
628 COMPtr<IWebBackForwardList> bfList;
629 if (FAILED(webView->backForwardList(&bfList)))
632 // Print out all items in the list after prevTestBFItem, which was from the previous test
633 // Gather items from the end of the list, the print them out from oldest to newest
635 Vector<COMPtr<IUnknown> > itemsToPrint;
637 int forwardListCount;
638 if (FAILED(bfList->forwardListCount(&forwardListCount)))
641 for (int i = forwardListCount; i > 0; --i) {
642 COMPtr<IWebHistoryItem> item;
643 if (FAILED(bfList->itemAtIndex(i, &item)))
645 // something is wrong if the item from the last test is in the forward part of the b/f list
646 assert(item != prevTestBFItem);
647 COMPtr<IUnknown> itemUnknown;
648 item->QueryInterface(&itemUnknown);
649 itemsToPrint.append(itemUnknown);
652 COMPtr<IWebHistoryItem> currentItem;
653 if (FAILED(bfList->currentItem(¤tItem)))
656 assert(currentItem != prevTestBFItem);
657 COMPtr<IUnknown> currentItemUnknown;
658 currentItem->QueryInterface(¤tItemUnknown);
659 itemsToPrint.append(currentItemUnknown);
660 int currentItemIndex = itemsToPrint.size() - 1;
663 if (FAILED(bfList->backListCount(&backListCount)))
666 for (int i = -1; i >= -backListCount; --i) {
667 COMPtr<IWebHistoryItem> item;
668 if (FAILED(bfList->itemAtIndex(i, &item)))
670 if (item == prevTestBFItem)
672 COMPtr<IUnknown> itemUnknown;
673 item->QueryInterface(&itemUnknown);
674 itemsToPrint.append(itemUnknown);
677 for (int i = itemsToPrint.size() - 1; i >= 0; --i) {
678 COMPtr<IWebHistoryItem> historyItemToPrint;
679 itemsToPrint[i]->QueryInterface(&historyItemToPrint);
680 dumpHistoryItem(historyItemToPrint.get(), 8, i == currentItemIndex);
683 printf("===============================================\n");
686 static void dumpBackForwardListForAllWindows()
688 unsigned count = openWindows().size();
689 for (unsigned i = 0; i < count; i++) {
690 HWND window = openWindows()[i];
691 IWebView* webView = windowToWebViewMap().get(window).get();
692 dumpBackForwardList(webView);
696 static void invalidateAnyPreviousWaitToDumpWatchdog()
698 if (!waitToDumpWatchdog)
701 KillTimer(0, waitToDumpWatchdog);
702 waitToDumpWatchdog = 0;
707 invalidateAnyPreviousWaitToDumpWatchdog();
709 COMPtr<IWebDataSource> dataSource;
710 if (SUCCEEDED(frame->dataSource(&dataSource))) {
711 COMPtr<IWebURLResponse> response;
712 if (SUCCEEDED(dataSource->response(&response)) && response) {
714 if (SUCCEEDED(response->MIMEType(&mimeType)) && !_tcscmp(mimeType, TEXT("text/plain"))) {
715 ::gLayoutTestController->setDumpAsText(true);
716 ::gLayoutTestController->setGeneratePixelResults(false);
718 SysFreeString(mimeType);
722 BSTR resultString = 0;
725 if (::gLayoutTestController->dumpAsText()) {
726 ::InvalidateRect(webViewWindow, 0, TRUE);
727 ::SendMessage(webViewWindow, WM_PAINT, 0, 0);
728 wstring result = dumpFramesAsText(frame);
729 resultString = SysAllocStringLen(result.data(), result.size());
731 bool isSVGW3CTest = (gLayoutTestController->testPathOrURL().find("svg\\W3C-SVG-1.1") != string::npos);
738 width = LayoutTestController::maxViewWidth;
739 height = LayoutTestController::maxViewHeight;
742 ::SetWindowPos(webViewWindow, 0, 0, 0, width, height, SWP_NOMOVE);
743 ::InvalidateRect(webViewWindow, 0, TRUE);
744 ::SendMessage(webViewWindow, WM_PAINT, 0, 0);
746 COMPtr<IWebFramePrivate> framePrivate;
747 if (FAILED(frame->QueryInterface(&framePrivate)))
749 framePrivate->renderTreeAsExternalRepresentation(gLayoutTestController->isPrinting(), &resultString);
753 printf("ERROR: nil result from %s", ::gLayoutTestController->dumpAsText() ? "IDOMElement::innerText" : "IFrameViewPrivate::renderTreeAsExternalRepresentation");
755 unsigned stringLength = SysStringLen(resultString);
756 int bufferSize = ::WideCharToMultiByte(CP_UTF8, 0, resultString, stringLength, 0, 0, 0, 0);
757 char* buffer = (char*)malloc(bufferSize + 1);
758 ::WideCharToMultiByte(CP_UTF8, 0, resultString, stringLength, buffer, bufferSize + 1, 0, 0);
759 fwrite(buffer, 1, bufferSize, stdout);
761 if (!::gLayoutTestController->dumpAsText())
762 dumpFrameScrollPosition(frame);
764 if (::gLayoutTestController->dumpBackForwardList())
765 dumpBackForwardListForAllWindows();
768 if (printSeparators) {
769 puts("#EOF"); // terminate the content block
770 fputs("#EOF\n", stderr);
776 && gLayoutTestController->generatePixelResults()
777 && !gLayoutTestController->dumpDOMAsWebArchive()
778 && !gLayoutTestController->dumpSourceAsWebArchive())
779 dumpWebViewAsPixelsAndCompareWithExpected(gLayoutTestController->expectedPixelHash());
781 printf("#EOF\n"); // terminate the (possibly empty) pixels block
785 SysFreeString(resultString);
786 // This will exit from our message loop.
791 static bool shouldLogFrameLoadDelegates(const char* pathOrURL)
793 return strstr(pathOrURL, "/loading/") || strstr(pathOrURL, "\\loading\\");
796 static bool shouldLogHistoryDelegates(const char* pathOrURL)
798 return strstr(pathOrURL, "/globalhistory/") || strstr(pathOrURL, "\\globalhistory\\");
801 static bool shouldOpenWebInspector(const char* pathOrURL)
803 return strstr(pathOrURL, "/inspector/") || strstr(pathOrURL, "\\inspector\\");
806 static bool shouldDumpAsText(const char* pathOrURL)
808 return strstr(pathOrURL, "/dumpAsText/") || strstr(pathOrURL, "\\dumpAsText\\");
811 static bool shouldEnableDeveloperExtras(const char* pathOrURL)
816 static void resetDefaultsToConsistentValues(IWebPreferences* preferences)
819 static BSTR standardFamily = SysAllocString(TEXT("Times"));
820 static BSTR fixedFamily = SysAllocString(TEXT("Courier"));
821 static BSTR sansSerifFamily = SysAllocString(TEXT("Helvetica"));
822 static BSTR cursiveFamily = SysAllocString(TEXT("Apple Chancery"));
823 static BSTR fantasyFamily = SysAllocString(TEXT("Papyrus"));
824 static BSTR pictographFamily = SysAllocString(TEXT("Apple Color Emoji"));
826 static BSTR standardFamily = SysAllocString(TEXT("Times New Roman"));
827 static BSTR fixedFamily = SysAllocString(TEXT("Courier New"));
828 static BSTR sansSerifFamily = SysAllocString(TEXT("Arial"));
829 static BSTR cursiveFamily = SysAllocString(TEXT("Comic Sans MS")); // Not actually cursive, but it's what IE and Firefox use.
830 static BSTR fantasyFamily = SysAllocString(TEXT("Times New Roman"));
831 static BSTR pictographFamily = SysAllocString(TEXT("Times New Roman"));
834 preferences->setStandardFontFamily(standardFamily);
835 preferences->setFixedFontFamily(fixedFamily);
836 preferences->setSerifFontFamily(standardFamily);
837 preferences->setSansSerifFontFamily(sansSerifFamily);
838 preferences->setCursiveFontFamily(cursiveFamily);
839 preferences->setFantasyFontFamily(fantasyFamily);
840 preferences->setPictographFontFamily(pictographFamily);
842 preferences->setAutosaves(FALSE);
843 preferences->setDefaultFontSize(16);
844 preferences->setDefaultFixedFontSize(13);
845 preferences->setMinimumFontSize(0);
846 preferences->setJavaEnabled(FALSE);
847 preferences->setPlugInsEnabled(TRUE);
848 preferences->setDOMPasteAllowed(TRUE);
849 preferences->setEditableLinkBehavior(WebKitEditableLinkOnlyLiveWithShiftKey);
850 preferences->setFontSmoothing(FontSmoothingTypeStandard);
851 preferences->setUsesPageCache(FALSE);
852 preferences->setPrivateBrowsingEnabled(FALSE);
853 preferences->setJavaScriptCanOpenWindowsAutomatically(TRUE);
854 preferences->setJavaScriptEnabled(TRUE);
855 preferences->setTabsToLinks(FALSE);
856 preferences->setShouldPrintBackgrounds(TRUE);
857 preferences->setLoadsImagesAutomatically(TRUE);
858 preferences->setEditingBehavior(WebKitEditingWinBehavior);
860 if (persistentUserStyleSheetLocation) {
861 Vector<wchar_t> urlCharacters(CFStringGetLength(persistentUserStyleSheetLocation.get()));
862 CFStringGetCharacters(persistentUserStyleSheetLocation.get(), CFRangeMake(0, CFStringGetLength(persistentUserStyleSheetLocation.get())), (UniChar *)urlCharacters.data());
863 BSTR url = SysAllocStringLen(urlCharacters.data(), urlCharacters.size());
864 preferences->setUserStyleSheetLocation(url);
866 preferences->setUserStyleSheetEnabled(TRUE);
868 preferences->setUserStyleSheetEnabled(FALSE);
870 COMPtr<IWebPreferencesPrivate> prefsPrivate(Query, preferences);
872 prefsPrivate->setAllowUniversalAccessFromFileURLs(TRUE);
873 prefsPrivate->setAllowFileAccessFromFileURLs(TRUE);
874 prefsPrivate->setAuthorAndUserStylesEnabled(TRUE);
875 prefsPrivate->setDeveloperExtrasEnabled(FALSE);
876 prefsPrivate->setExperimentalNotificationsEnabled(TRUE);
877 prefsPrivate->setShouldPaintNativeControls(FALSE); // FIXME - need to make DRT pass with Windows native controls <http://bugs.webkit.org/show_bug.cgi?id=25592>
878 prefsPrivate->setJavaScriptCanAccessClipboard(TRUE);
879 prefsPrivate->setXSSAuditorEnabled(FALSE);
880 prefsPrivate->setFrameFlatteningEnabled(FALSE);
881 prefsPrivate->setOfflineWebApplicationCacheEnabled(TRUE);
882 prefsPrivate->setLoadsSiteIconsIgnoringImageLoadingPreference(FALSE);
883 prefsPrivate->setHixie76WebSocketProtocolEnabled(TRUE);
885 setAlwaysAcceptCookies(false);
887 setlocale(LC_ALL, "");
890 static void resetWebViewToConsistentStateBeforeTesting()
892 COMPtr<IWebView> webView;
893 if (FAILED(frame->webView(&webView)))
896 webView->setPolicyDelegate(0);
897 policyDelegate->setPermissive(false);
898 policyDelegate->setControllerToNotifyDone(0);
900 COMPtr<IWebIBActions> webIBActions(Query, webView);
902 webIBActions->makeTextStandardSize(0);
903 webIBActions->resetPageZoom(0);
907 COMPtr<IWebPreferences> preferences;
908 if (SUCCEEDED(webView->preferences(&preferences)))
909 resetDefaultsToConsistentValues(preferences.get());
911 COMPtr<IWebViewEditing> viewEditing;
912 if (SUCCEEDED(webView->QueryInterface(&viewEditing)))
913 viewEditing->setSmartInsertDeleteEnabled(TRUE);
915 COMPtr<IWebViewPrivate> webViewPrivate(Query, webView);
919 double minimumInterval = 0;
920 if (SUCCEEDED(webViewPrivate->defaultMinimumTimerInterval(&minimumInterval)))
921 webViewPrivate->setMinimumTimerInterval(minimumInterval);
923 COMPtr<IWebInspector> inspector;
924 if (SUCCEEDED(webViewPrivate->inspector(&inspector)))
925 inspector->setJavaScriptProfilingEnabled(FALSE);
928 if (SUCCEEDED(webViewPrivate->viewWindow(reinterpret_cast<OLE_HANDLE*>(&viewWindow))) && viewWindow)
929 SetFocus(viewWindow);
931 webViewPrivate->clearMainFrameName();
932 webViewPrivate->resetOriginAccessWhitelists();
935 if (SUCCEEDED(webView->groupName(&groupName))) {
936 webViewPrivate->removeAllUserContentFromGroup(groupName);
937 SysFreeString(groupName);
940 sharedUIDelegate->resetUndoManager();
942 sharedFrameLoadDelegate->resetToConsistentState();
944 COMPtr<IWebFramePrivate> framePrivate;
945 if (SUCCEEDED(frame->QueryInterface(&framePrivate)))
946 framePrivate->clearOpener();
949 static void runTest(const string& testPathOrURL)
951 static BSTR methodBStr = SysAllocString(TEXT("GET"));
953 // Look for "'" as a separator between the path or URL, and the pixel dump hash that follows.
954 string pathOrURL(testPathOrURL);
955 string expectedPixelHash;
957 size_t separatorPos = pathOrURL.find("'");
958 if (separatorPos != string::npos) {
959 pathOrURL = string(testPathOrURL, 0, separatorPos);
960 expectedPixelHash = string(testPathOrURL, separatorPos + 1);
965 CFStringRef str = CFStringCreateWithCString(0, pathOrURL.c_str(), kCFStringEncodingWindowsLatin1);
966 CFURLRef url = CFURLCreateWithString(0, str, 0);
969 url = CFURLCreateWithFileSystemPath(0, str, kCFURLWindowsPathStyle, false);
973 str = CFURLGetString(url);
975 CFIndex length = CFStringGetLength(str);
976 UniChar* buffer = new UniChar[length];
978 CFStringGetCharacters(str, CFRangeMake(0, length), buffer);
979 urlBStr = SysAllocStringLen((OLECHAR*)buffer, length);
984 ::gLayoutTestController = LayoutTestController::create(pathOrURL, expectedPixelHash);
988 gLayoutTestController->setIconDatabaseEnabled(false);
990 if (shouldLogFrameLoadDelegates(pathOrURL.c_str()))
991 gLayoutTestController->setDumpFrameLoadCallbacks(true);
993 COMPtr<IWebView> webView;
994 if (SUCCEEDED(frame->webView(&webView))) {
995 COMPtr<IWebViewPrivate> viewPrivate;
996 if (SUCCEEDED(webView->QueryInterface(&viewPrivate))) {
997 if (shouldLogHistoryDelegates(pathOrURL.c_str())) {
998 gLayoutTestController->setDumpHistoryDelegateCallbacks(true);
999 viewPrivate->setHistoryDelegate(sharedHistoryDelegate.get());
1001 viewPrivate->setHistoryDelegate(0);
1004 COMPtr<IWebHistory> history;
1005 if (SUCCEEDED(WebKitCreateInstance(CLSID_WebHistory, 0, __uuidof(history), reinterpret_cast<void**>(&history))))
1006 history->setOptionalSharedHistory(0);
1008 resetWebViewToConsistentStateBeforeTesting();
1010 if (shouldEnableDeveloperExtras(pathOrURL.c_str())) {
1011 gLayoutTestController->setDeveloperExtrasEnabled(true);
1012 if (shouldOpenWebInspector(pathOrURL.c_str()))
1013 gLayoutTestController->showWebInspector();
1015 if (shouldDumpAsText(pathOrURL.c_str())) {
1016 gLayoutTestController->setDumpAsText(true);
1017 gLayoutTestController->setGeneratePixelResults(false);
1022 COMPtr<IWebBackForwardList> bfList;
1023 if (SUCCEEDED(webView->backForwardList(&bfList)))
1024 bfList->currentItem(&prevTestBFItem);
1027 WorkQueue::shared()->clear();
1028 WorkQueue::shared()->setFrozen(false);
1031 webView->hostWindow(reinterpret_cast<OLE_HANDLE*>(&hostWindow));
1033 COMPtr<IWebMutableURLRequest> request;
1034 HRESULT hr = WebKitCreateInstance(CLSID_WebMutableURLRequest, 0, IID_IWebMutableURLRequest, (void**)&request);
1038 request->initWithURL(urlBStr, WebURLRequestUseProtocolCachePolicy, 60);
1040 request->setHTTPMethod(methodBStr);
1041 frame->loadRequest(request.get());
1044 while (GetMessage(&msg, 0, 0, 0)) {
1045 // We get spurious WM_MOUSELEAVE events which make event handling machinery think that mouse button
1046 // is released during dragging (see e.g. fast\dynamic\layer-hit-test-crash.html).
1047 // Mouse can never leave WebView during normal DumpRenderTree operation, so we just ignore all such events.
1048 if (msg.message == WM_MOUSELEAVE)
1050 TranslateMessage(&msg);
1051 DispatchMessage(&msg);
1054 if (shouldEnableDeveloperExtras(pathOrURL.c_str())) {
1055 gLayoutTestController->closeWebInspector();
1056 gLayoutTestController->setDeveloperExtrasEnabled(false);
1059 resetWebViewToConsistentStateBeforeTesting();
1061 frame->stopLoading();
1063 if (::gLayoutTestController->closeRemainingWindowsWhenComplete()) {
1064 Vector<HWND> windows = openWindows();
1065 unsigned size = windows.size();
1066 for (unsigned i = 0; i < size; i++) {
1067 HWND window = windows[i];
1069 // Don't try to close the main window
1070 if (window == hostWindow)
1073 DestroyWindow(window);
1078 SysFreeString(urlBStr);
1079 ::gLayoutTestController.clear();
1084 static Boolean pthreadEqualCallback(const void* value1, const void* value2)
1086 return (Boolean)pthread_equal(*(pthread_t*)value1, *(pthread_t*)value2);
1089 static CFDictionaryKeyCallBacks pthreadKeyCallbacks = { 0, 0, 0, 0, pthreadEqualCallback, 0 };
1091 static pthread_mutex_t javaScriptThreadsMutex = PTHREAD_MUTEX_INITIALIZER;
1092 static bool javaScriptThreadsShouldTerminate;
1094 static const int javaScriptThreadsCount = 4;
1095 static CFMutableDictionaryRef javaScriptThreads()
1097 assert(pthread_mutex_trylock(&javaScriptThreadsMutex) == EBUSY);
1098 static CFMutableDictionaryRef staticJavaScriptThreads;
1099 if (!staticJavaScriptThreads)
1100 staticJavaScriptThreads = CFDictionaryCreateMutable(0, 0, &pthreadKeyCallbacks, 0);
1101 return staticJavaScriptThreads;
1104 // Loops forever, running a script and randomly respawning, until
1105 // javaScriptThreadsShouldTerminate becomes true.
1106 void* runJavaScriptThread(void* arg)
1108 const char* const script =
1111 for (var i = 0; i < 10; i++) { \
1112 array.push(String(i)); \
1117 JSGlobalContextRef ctx = JSGlobalContextCreate(0);
1118 JSStringRef scriptRef = JSStringCreateWithUTF8CString(script);
1120 JSValueRef exception = 0;
1121 JSEvaluateScript(ctx, scriptRef, 0, 0, 1, &exception);
1124 JSGlobalContextRelease(ctx);
1125 JSStringRelease(scriptRef);
1127 JSGarbageCollect(ctx);
1129 pthread_mutex_lock(&javaScriptThreadsMutex);
1131 // Check for cancellation.
1132 if (javaScriptThreadsShouldTerminate) {
1133 pthread_mutex_unlock(&javaScriptThreadsMutex);
1137 // Respawn probabilistically.
1138 if (rand() % 5 == 0) {
1140 pthread_create(&pthread, 0, &runJavaScriptThread, 0);
1141 pthread_detach(pthread);
1143 pthread_t self = pthread_self();
1144 CFDictionaryRemoveValue(javaScriptThreads(), self.p);
1145 CFDictionaryAddValue(javaScriptThreads(), pthread.p, 0);
1147 pthread_mutex_unlock(&javaScriptThreadsMutex);
1151 pthread_mutex_unlock(&javaScriptThreadsMutex);
1155 static void startJavaScriptThreads(void)
1157 pthread_mutex_lock(&javaScriptThreadsMutex);
1159 for (int i = 0; i < javaScriptThreadsCount; i++) {
1161 pthread_create(&pthread, 0, &runJavaScriptThread, 0);
1162 pthread_detach(pthread);
1163 CFDictionaryAddValue(javaScriptThreads(), pthread.p, 0);
1166 pthread_mutex_unlock(&javaScriptThreadsMutex);
1169 static void stopJavaScriptThreads(void)
1171 pthread_mutex_lock(&javaScriptThreadsMutex);
1173 javaScriptThreadsShouldTerminate = true;
1175 pthread_t* pthreads[javaScriptThreadsCount] = {0};
1176 int threadDictCount = CFDictionaryGetCount(javaScriptThreads());
1177 assert(threadDictCount == javaScriptThreadsCount);
1178 CFDictionaryGetKeysAndValues(javaScriptThreads(), (const void**)pthreads, 0);
1180 pthread_mutex_unlock(&javaScriptThreadsMutex);
1182 for (int i = 0; i < javaScriptThreadsCount; i++) {
1183 pthread_t* pthread = pthreads[i];
1184 pthread_join(*pthread, 0);
1189 Vector<HWND>& openWindows()
1191 static Vector<HWND> vector;
1195 WindowToWebViewMap& windowToWebViewMap()
1197 static WindowToWebViewMap map;
1201 IWebView* createWebViewAndOffscreenWindow(HWND* webViewWindow)
1203 unsigned maxViewWidth = LayoutTestController::maxViewWidth;
1204 unsigned maxViewHeight = LayoutTestController::maxViewHeight;
1205 HWND hostWindow = CreateWindowEx(WS_EX_TOOLWINDOW, kDumpRenderTreeClassName, TEXT("DumpRenderTree"), WS_POPUP,
1206 -maxViewWidth, -maxViewHeight, maxViewWidth, maxViewHeight, 0, 0, GetModuleHandle(0), 0);
1210 HRESULT hr = WebKitCreateInstance(CLSID_WebView, 0, IID_IWebView, (void**)&webView);
1212 fprintf(stderr, "Failed to create CLSID_WebView instance, error 0x%x\n", hr);
1216 if (FAILED(webView->setHostWindow((OLE_HANDLE)(ULONG64)hostWindow)))
1220 clientRect.bottom = clientRect.left = clientRect.top = clientRect.right = 0;
1221 BSTR groupName = SysAllocString(L"org.webkit.DumpRenderTree");
1222 bool failed = FAILED(webView->initWithFrame(clientRect, 0, groupName));
1223 SysFreeString(groupName);
1227 COMPtr<IWebViewPrivate> viewPrivate;
1228 if (FAILED(webView->QueryInterface(&viewPrivate)))
1231 viewPrivate->setShouldApplyMacFontAscentHack(TRUE);
1232 viewPrivate->setAlwaysUsesComplexTextCodePath(forceComplexText);
1234 BSTR pluginPath = SysAllocStringLen(0, exePath().length() + _tcslen(TestPluginDir));
1235 _tcscpy(pluginPath, exePath().c_str());
1236 _tcscat(pluginPath, TestPluginDir);
1237 failed = FAILED(viewPrivate->addAdditionalPluginDirectory(pluginPath));
1238 SysFreeString(pluginPath);
1243 if (FAILED(viewPrivate->viewWindow(reinterpret_cast<OLE_HANDLE*>(&viewWindow))))
1246 *webViewWindow = viewWindow;
1248 SetWindowPos(viewWindow, 0, 0, 0, maxViewWidth, maxViewHeight, 0);
1249 ShowWindow(hostWindow, SW_SHOW);
1251 if (FAILED(webView->setFrameLoadDelegate(sharedFrameLoadDelegate.get())))
1254 if (FAILED(viewPrivate->setFrameLoadDelegatePrivate(sharedFrameLoadDelegate.get())))
1257 if (FAILED(webView->setUIDelegate(sharedUIDelegate.get())))
1260 COMPtr<IWebViewEditing> viewEditing;
1261 if (FAILED(webView->QueryInterface(&viewEditing)))
1264 if (FAILED(viewEditing->setEditingDelegate(sharedEditingDelegate.get())))
1267 ResourceLoadDelegate* resourceLoadDelegate = new ResourceLoadDelegate();
1268 HRESULT result = webView->setResourceLoadDelegate(resourceLoadDelegate);
1269 resourceLoadDelegate->Release(); // The delegate is owned by the WebView, so release our reference to it.
1273 openWindows().append(hostWindow);
1274 windowToWebViewMap().set(hostWindow, webView);
1279 RetainPtr<CFURLCacheRef> sharedCFURLCache()
1282 HMODULE module = GetModuleHandle(TEXT("CFNetwork.dll"));
1284 HMODULE module = GetModuleHandle(TEXT("CFNetwork_debug.dll"));
1289 typedef CFURLCacheRef (*CFURLCacheCopySharedURLCacheProcPtr)(void);
1290 if (CFURLCacheCopySharedURLCacheProcPtr copyCache = reinterpret_cast<CFURLCacheCopySharedURLCacheProcPtr>(GetProcAddress(module, "CFURLCacheCopySharedURLCache")))
1291 return RetainPtr<CFURLCacheRef>(AdoptCF, copyCache());
1293 typedef CFURLCacheRef (*CFURLCacheSharedURLCacheProcPtr)(void);
1294 if (CFURLCacheSharedURLCacheProcPtr sharedCache = reinterpret_cast<CFURLCacheSharedURLCacheProcPtr>(GetProcAddress(module, "CFURLCacheSharedURLCache")))
1295 return sharedCache();
1301 static LONG WINAPI exceptionFilter(EXCEPTION_POINTERS*)
1303 fputs("#CRASHED\n", stderr);
1305 return EXCEPTION_CONTINUE_SEARCH;
1308 int main(int argc, char* argv[])
1310 // Cygwin calls ::SetErrorMode(SEM_FAILCRITICALERRORS), which we will inherit. This is bad for
1311 // testing/debugging, as it causes the post-mortem debugger not to be invoked. We reset the
1312 // error mode here to work around Cygwin's behavior. See <http://webkit.org/b/55222>.
1315 ::SetUnhandledExceptionFilter(exceptionFilter);
1317 leakChecking = false;
1319 _setmode(1, _O_BINARY);
1320 _setmode(2, _O_BINARY);
1324 Vector<const char*> tests;
1326 for (int i = 1; i < argc; ++i) {
1327 if (!stricmp(argv[i], "--threaded")) {
1332 if (!stricmp(argv[i], "--dump-all-pixels")) {
1333 dumpAllPixels = true;
1337 if (!stricmp(argv[i], "--pixel-tests")) {
1342 if (!stricmp(argv[i], "--complex-text")) {
1343 forceComplexText = true;
1347 if (!stricmp(argv[i], "--print-supported-features")) {
1348 printSupportedFeatures = true;
1352 tests.append(argv[i]);
1355 policyDelegate = new PolicyDelegate();
1356 sharedFrameLoadDelegate.adoptRef(new FrameLoadDelegate);
1357 sharedUIDelegate.adoptRef(new UIDelegate);
1358 sharedEditingDelegate.adoptRef(new EditingDelegate);
1359 sharedHistoryDelegate.adoptRef(new HistoryDelegate);
1361 // FIXME - need to make DRT pass with Windows native controls <http://bugs.webkit.org/show_bug.cgi?id=25592>
1362 COMPtr<IWebPreferences> tmpPreferences;
1363 if (FAILED(WebKitCreateInstance(CLSID_WebPreferences, 0, IID_IWebPreferences, reinterpret_cast<void**>(&tmpPreferences))))
1365 COMPtr<IWebPreferences> standardPreferences;
1366 if (FAILED(tmpPreferences->standardPreferences(&standardPreferences)))
1368 COMPtr<IWebPreferencesPrivate> standardPreferencesPrivate;
1369 if (FAILED(standardPreferences->QueryInterface(&standardPreferencesPrivate)))
1371 standardPreferencesPrivate->setShouldPaintNativeControls(FALSE);
1372 standardPreferences->setJavaScriptEnabled(TRUE);
1373 standardPreferences->setDefaultFontSize(16);
1374 standardPreferences->setAcceleratedCompositingEnabled(true);
1375 standardPreferences->setContinuousSpellCheckingEnabled(TRUE);
1377 if (printSupportedFeatures) {
1378 BOOL acceleratedCompositingAvailable;
1379 standardPreferences->acceleratedCompositingEnabled(&acceleratedCompositingAvailable);
1381 #if ENABLE(3D_RENDERING)
1382 // In theory, we could have a software-based 3D rendering implementation that we use when
1383 // hardware-acceleration is not available. But we don't have any such software
1384 // implementation, so 3D rendering is only available when hardware-acceleration is.
1385 BOOL threeDRenderingAvailable = acceleratedCompositingAvailable;
1387 BOOL threeDRenderingAvailable = FALSE;
1390 printf("SupportedFeatures:%s %s\n", acceleratedCompositingAvailable ? "AcceleratedCompositing" : "", threeDRenderingAvailable ? "3DRendering" : "");
1394 COMPtr<IWebView> webView(AdoptCOM, createWebViewAndOffscreenWindow(&webViewWindow));
1398 COMPtr<IWebIconDatabase> iconDatabase;
1399 COMPtr<IWebIconDatabase> tmpIconDatabase;
1400 if (FAILED(WebKitCreateInstance(CLSID_WebIconDatabase, 0, IID_IWebIconDatabase, (void**)&tmpIconDatabase)))
1402 if (FAILED(tmpIconDatabase->sharedIconDatabase(&iconDatabase)))
1405 if (FAILED(webView->mainFrame(&frame)))
1409 RetainPtr<CFURLCacheRef> urlCache = sharedCFURLCache();
1410 CFURLCacheRemoveAllCachedResponses(urlCache.get());
1414 _CrtMemState entryToMainMemCheckpoint;
1416 _CrtMemCheckpoint(&entryToMainMemCheckpoint);
1420 startJavaScriptThreads();
1422 if (tests.size() == 1 && !strcmp(tests[0], "-")) {
1423 char filenameBuffer[2048];
1424 printSeparators = true;
1425 while (fgets(filenameBuffer, sizeof(filenameBuffer), stdin)) {
1426 char* newLineCharacter = strchr(filenameBuffer, '\n');
1427 if (newLineCharacter)
1428 *newLineCharacter = '\0';
1430 if (strlen(filenameBuffer) == 0)
1433 runTest(filenameBuffer);
1436 printSeparators = tests.size() > 1;
1437 for (int i = 0; i < tests.size(); i++)
1442 stopJavaScriptThreads();
1444 delete policyDelegate;
1449 // dump leaks to stderr
1450 _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE);
1451 _CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDERR);
1452 _CrtMemDumpAllObjectsSince(&entryToMainMemCheckpoint);