64a107ed5876d9489c5c0b790e73e02a954c6a5f
[WebKit-https.git] / Tools / DumpRenderTree / win / TestRunnerWin.cpp
1 /*
2  * Copyright (C) 2006, 2007, 2008, 2009, 2010, 2012, 2013 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  *
8  * 1.  Redistributions of source code must retain the above copyright
9  *     notice, this list of conditions and the following disclaimer.
10  * 2.  Redistributions in binary form must reproduce the above copyright
11  *     notice, this list of conditions and the following disclaimer in the
12  *     documentation and/or other materials provided with the distribution.
13  * 3.  Neither the name of Apple Inc. ("Apple") nor the names of
14  *     its contributors may be used to endorse or promote products derived
15  *     from this software without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
18  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20  * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
21  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  */
28
29 #include "config.h"
30 #include "TestRunner.h"
31
32 #include "DumpRenderTree.h"
33 #include "EditingDelegate.h"
34 #include "PolicyDelegate.h"
35 #include "WorkQueue.h"
36 #include "WorkQueueItem.h"
37 #include <CoreFoundation/CoreFoundation.h>
38 #include <JavaScriptCore/JSRetainPtr.h>
39 #include <JavaScriptCore/JSStringRefBSTR.h>
40 #include <JavaScriptCore/JavaScriptCore.h>
41 #include <WebCore/COMPtr.h>
42 #include <WebKit/WebKit.h>
43 #include <WebKit/WebKitCOMAPI.h>
44 #include <comutil.h>
45 #include <shlguid.h>
46 #include <shlwapi.h>
47 #include <shobjidl.h>
48 #include <string>
49 #include <wtf/Assertions.h>
50 #include <wtf/Platform.h>
51 #include <wtf/RetainPtr.h>
52 #include <wtf/Vector.h>
53
54 using std::string;
55 using std::wstring;
56
57 static bool resolveCygwinPath(const wstring& cygwinPath, wstring& windowsPath);
58
59 TestRunner::~TestRunner()
60 {
61     COMPtr<IWebView> webView;
62     if (FAILED(frame->webView(&webView)))
63         return;
64
65     // reset webview-related states back to default values in preparation for next test
66
67     COMPtr<IWebViewPrivate> viewPrivate;
68     if (SUCCEEDED(webView->QueryInterface(&viewPrivate)))
69         viewPrivate->setTabKeyCyclesThroughElements(TRUE);
70
71     COMPtr<IWebViewEditing> viewEditing;
72     if (FAILED(webView->QueryInterface(&viewEditing)))
73         return;
74     COMPtr<IWebEditingDelegate> delegate;
75     if (FAILED(viewEditing->editingDelegate(&delegate)))
76         return;
77     COMPtr<EditingDelegate> editingDelegate(Query, viewEditing.get());
78     if (editingDelegate)
79         editingDelegate->setAcceptsEditing(TRUE);
80 }
81
82 void TestRunner::addDisallowedURL(JSStringRef url)
83 {
84     // FIXME: Implement!
85 }
86
87 void TestRunner::clearBackForwardList()
88 {
89     COMPtr<IWebView> webView;
90     if (FAILED(frame->webView(&webView)))
91         return;
92
93     COMPtr<IWebBackForwardList> backForwardList;
94     if (FAILED(webView->backForwardList(&backForwardList)))
95         return;
96
97     COMPtr<IWebHistoryItem> item;
98     if (FAILED(backForwardList->currentItem(&item)))
99         return;
100
101     // We clear the history by setting the back/forward list's capacity to 0
102     // then restoring it back and adding back the current item.
103     int capacity;
104     if (FAILED(backForwardList->capacity(&capacity)))
105         return;
106
107     backForwardList->setCapacity(0);
108     backForwardList->setCapacity(capacity);
109     backForwardList->addItem(item.get());
110     backForwardList->goToItem(item.get());
111 }
112
113 bool TestRunner::callShouldCloseOnWebView()
114 {
115     COMPtr<IWebView> webView;
116     if (FAILED(frame->webView(&webView)))
117         return false;
118
119     COMPtr<IWebViewPrivate> viewPrivate;
120     if (FAILED(webView->QueryInterface(&viewPrivate)))
121         return false;
122
123     BOOL result;
124     viewPrivate->shouldClose(&result);
125     return result;
126 }
127
128 JSStringRef TestRunner::copyDecodedHostName(JSStringRef name)
129 {
130     // FIXME: Implement!
131     return 0;
132 }
133
134 JSStringRef TestRunner::copyEncodedHostName(JSStringRef name)
135 {
136     // FIXME: Implement!
137     return 0;
138 }
139
140 void TestRunner::dispatchPendingLoadRequests()
141 {
142     // FIXME: Implement for testing fix for 6727495
143 }
144
145 void TestRunner::display()
146 {
147     displayWebView();
148 }
149
150 void TestRunner::keepWebHistory()
151 {
152     COMPtr<IWebHistory> history;
153     if (FAILED(WebKitCreateInstance(CLSID_WebHistory, 0, __uuidof(history), reinterpret_cast<void**>(&history))))
154         return;
155
156     COMPtr<IWebHistory> sharedHistory;
157     if (FAILED(WebKitCreateInstance(CLSID_WebHistory, 0, __uuidof(sharedHistory), reinterpret_cast<void**>(&sharedHistory))))
158         return;
159
160     history->setOptionalSharedHistory(sharedHistory.get());
161 }
162
163 void TestRunner::waitForPolicyDelegate()
164 {
165     COMPtr<IWebView> webView;
166     if (FAILED(frame->webView(&webView)))
167         return;
168
169     setWaitToDump(true);
170     policyDelegate->setControllerToNotifyDone(this);
171     webView->setPolicyDelegate(policyDelegate);
172 }
173
174 size_t TestRunner::webHistoryItemCount()
175 {
176     COMPtr<IWebHistory> history;
177     if (FAILED(WebKitCreateInstance(CLSID_WebHistory, 0, __uuidof(history), reinterpret_cast<void**>(&history))))
178         return 0;
179
180     COMPtr<IWebHistory> sharedHistory;
181     if (FAILED(history->optionalSharedHistory(&sharedHistory)) || !sharedHistory)
182         return 0;
183
184     COMPtr<IWebHistoryPrivate> sharedHistoryPrivate;
185     if (FAILED(sharedHistory->QueryInterface(&sharedHistoryPrivate)))
186         return 0;
187
188     int count;
189     if (FAILED(sharedHistoryPrivate->allItems(&count, 0)))
190         return 0;
191
192     return count;
193 }
194
195 void TestRunner::notifyDone()
196 {
197     // Same as on mac.  This can be shared.
198     if (m_waitToDump && !topLoadingFrame && !WorkQueue::shared()->count())
199         dump();
200     m_waitToDump = false;
201 }
202
203 JSStringRef TestRunner::pathToLocalResource(JSContextRef context, JSStringRef url)
204 {
205     wstring input(JSStringGetCharactersPtr(url), JSStringGetLength(url));
206
207     wstring localPath;
208     if (!resolveCygwinPath(input, localPath)) {
209         printf("ERROR: Failed to resolve Cygwin path %S\n", input.c_str());
210         return 0;
211     }
212
213     return JSStringCreateWithCharacters(localPath.c_str(), localPath.length());
214 }
215
216 static wstring jsStringRefToWString(JSStringRef jsStr)
217 {
218     size_t length = JSStringGetLength(jsStr);
219     Vector<WCHAR> buffer(length + 1);
220     memcpy(buffer.data(), JSStringGetCharactersPtr(jsStr), length * sizeof(WCHAR));
221     buffer[length] = '\0';
222
223     return buffer.data();
224 }
225
226 void TestRunner::queueLoad(JSStringRef url, JSStringRef target)
227 {
228     COMPtr<IWebDataSource> dataSource;
229     if (FAILED(frame->dataSource(&dataSource)))
230         return;
231
232     COMPtr<IWebURLResponse> response;
233     if (FAILED(dataSource->response(&response)) || !response)
234         return;
235
236     BSTR responseURLBSTR;
237     if (FAILED(response->URL(&responseURLBSTR)))
238         return;
239     wstring responseURL(responseURLBSTR, SysStringLen(responseURLBSTR));
240     SysFreeString(responseURLBSTR);
241
242     // FIXME: We should do real relative URL resolution here.
243     int lastSlash = responseURL.rfind('/');
244     if (lastSlash != -1)
245         responseURL = responseURL.substr(0, lastSlash);
246
247     wstring wURL = jsStringRefToWString(url);
248     wstring wAbsoluteURL = responseURL + TEXT("/") + wURL;
249     JSRetainPtr<JSStringRef> jsAbsoluteURL(Adopt, JSStringCreateWithCharacters(wAbsoluteURL.data(), wAbsoluteURL.length()));
250
251     WorkQueue::shared()->queue(new LoadItem(jsAbsoluteURL.get(), target));
252 }
253
254 void TestRunner::setAcceptsEditing(bool acceptsEditing)
255 {
256     COMPtr<IWebView> webView;
257     if (FAILED(frame->webView(&webView)))
258         return;
259
260     COMPtr<IWebViewEditing> viewEditing;
261     if (FAILED(webView->QueryInterface(&viewEditing)))
262         return;
263
264     COMPtr<IWebEditingDelegate> delegate;
265     if (FAILED(viewEditing->editingDelegate(&delegate)))
266         return;
267
268     EditingDelegate* editingDelegate = (EditingDelegate*)(IWebEditingDelegate*)delegate.get();
269     editingDelegate->setAcceptsEditing(acceptsEditing);
270 }
271
272 void TestRunner::setAlwaysAcceptCookies(bool alwaysAcceptCookies)
273 {
274     if (alwaysAcceptCookies == m_alwaysAcceptCookies)
275         return;
276
277     if (!::setAlwaysAcceptCookies(alwaysAcceptCookies))
278         return;
279     m_alwaysAcceptCookies = alwaysAcceptCookies;
280 }
281
282 void TestRunner::setAuthorAndUserStylesEnabled(bool flag)
283 {
284     COMPtr<IWebView> webView;
285     if (FAILED(frame->webView(&webView)))
286         return;
287
288     COMPtr<IWebPreferences> preferences;
289     if (FAILED(webView->preferences(&preferences)))
290         return;
291
292     COMPtr<IWebPreferencesPrivate> prefsPrivate(Query, preferences);
293     if (!prefsPrivate)
294         return;
295
296     prefsPrivate->setAuthorAndUserStylesEnabled(flag);
297 }
298
299 void TestRunner::setCustomPolicyDelegate(bool setDelegate, bool permissive)
300 {
301     COMPtr<IWebView> webView;
302     if (FAILED(frame->webView(&webView)))
303         return;
304
305     if (setDelegate) {
306         policyDelegate->setPermissive(permissive);
307         webView->setPolicyDelegate(policyDelegate);
308     } else
309         webView->setPolicyDelegate(0);
310 }
311
312 void TestRunner::setMockDeviceOrientation(bool canProvideAlpha, double alpha, bool canProvideBeta, double beta, bool canProvideGamma, double gamma)
313 {
314     // FIXME: Implement for DeviceOrientation layout tests.
315     // See https://bugs.webkit.org/show_bug.cgi?id=30335.
316 }
317
318 void TestRunner::setMockGeolocationPosition(double latitude, double longitude, double accuracy, bool providesAltitude, double altitude, bool providesAltitudeAccuracy, double altitudeAccuracy, bool providesHeading, double heading, bool providesSpeed, double speed)
319 {
320     // FIXME: Implement for Geolocation layout tests.
321     // See https://bugs.webkit.org/show_bug.cgi?id=28264.
322 }
323
324 void TestRunner::setMockGeolocationPositionUnavailableError(JSStringRef message)
325 {
326     // FIXME: Implement for Geolocation layout tests.
327     // See https://bugs.webkit.org/show_bug.cgi?id=28264.
328 }
329
330 void TestRunner::setGeolocationPermission(bool allow)
331 {
332     // FIXME: Implement for Geolocation layout tests.
333     setGeolocationPermissionCommon(allow);
334 }
335
336 int TestRunner::numberOfPendingGeolocationPermissionRequests()
337 {
338     // FIXME: Implement for Geolocation layout tests.
339     return -1;
340 }
341
342 void TestRunner::addMockSpeechInputResult(JSStringRef result, double confidence, JSStringRef language)
343 {
344     // FIXME: Implement for speech input layout tests.
345     // See https://bugs.webkit.org/show_bug.cgi?id=39485.
346 }
347
348 void TestRunner::setMockSpeechInputDumpRect(bool flag)
349 {
350     // FIXME: Implement for speech input layout tests.
351     // See https://bugs.webkit.org/show_bug.cgi?id=39485.
352 }
353
354 void TestRunner::startSpeechInput(JSContextRef inputElement)
355 {
356     // FIXME: Implement for speech input layout tests.
357     // See https://bugs.webkit.org/show_bug.cgi?id=39485.
358 }
359
360 void TestRunner::setIconDatabaseEnabled(bool iconDatabaseEnabled)
361 {
362     // See also <rdar://problem/6480108>
363     COMPtr<IWebIconDatabase> iconDatabase;
364     COMPtr<IWebIconDatabase> tmpIconDatabase;
365     if (FAILED(WebKitCreateInstance(CLSID_WebIconDatabase, 0, IID_IWebIconDatabase, (void**)&tmpIconDatabase)))
366         return;
367     if (FAILED(tmpIconDatabase->sharedIconDatabase(&iconDatabase)))
368         return;
369
370     iconDatabase->setEnabled(iconDatabaseEnabled);
371 }
372
373 void TestRunner::setMainFrameIsFirstResponder(bool flag)
374 {
375     // FIXME: Implement!
376 }
377
378 void TestRunner::setPrivateBrowsingEnabled(bool privateBrowsingEnabled)
379 {
380     COMPtr<IWebView> webView;
381     if (FAILED(frame->webView(&webView)))
382         return;
383
384     COMPtr<IWebPreferences> preferences;
385     if (FAILED(webView->preferences(&preferences)))
386         return;
387
388     preferences->setPrivateBrowsingEnabled(privateBrowsingEnabled);
389 }
390
391 void TestRunner::setXSSAuditorEnabled(bool enabled)
392 {
393     COMPtr<IWebView> webView;
394     if (FAILED(frame->webView(&webView)))
395         return;
396
397     COMPtr<IWebPreferences> preferences;
398     if (FAILED(webView->preferences(&preferences)))
399         return;
400
401     COMPtr<IWebPreferencesPrivate> prefsPrivate(Query, preferences);
402     if (!prefsPrivate)
403         return;
404
405     prefsPrivate->setXSSAuditorEnabled(enabled);
406 }
407
408 void TestRunner::setSpatialNavigationEnabled(bool enabled)
409 {
410     // FIXME: Implement for SpatialNavigation layout tests.
411 }
412
413 void TestRunner::setAllowUniversalAccessFromFileURLs(bool enabled)
414 {
415     COMPtr<IWebView> webView;
416     if (FAILED(frame->webView(&webView)))
417         return;
418
419     COMPtr<IWebPreferences> preferences;
420     if (FAILED(webView->preferences(&preferences)))
421         return;
422
423     COMPtr<IWebPreferencesPrivate> prefsPrivate(Query, preferences);
424     if (!prefsPrivate)
425         return;
426
427     prefsPrivate->setAllowUniversalAccessFromFileURLs(enabled);
428 }
429
430 void TestRunner::setAllowFileAccessFromFileURLs(bool enabled)
431 {
432     COMPtr<IWebView> webView;
433     if (FAILED(frame->webView(&webView)))
434         return;
435
436     COMPtr<IWebPreferences> preferences;
437     if (FAILED(webView->preferences(&preferences)))
438         return;
439
440     COMPtr<IWebPreferencesPrivate> prefsPrivate(Query, preferences);
441     if (!prefsPrivate)
442         return;
443
444     prefsPrivate->setAllowFileAccessFromFileURLs(enabled);
445 }
446
447 void TestRunner::setPopupBlockingEnabled(bool enabled)
448 {
449     COMPtr<IWebView> webView;
450     if (FAILED(frame->webView(&webView)))
451         return;
452
453     COMPtr<IWebPreferences> preferences;
454     if (FAILED(webView->preferences(&preferences)))
455         return;
456
457     preferences->setJavaScriptCanOpenWindowsAutomatically(!enabled);
458 }
459
460 void TestRunner::setPluginsEnabled(bool flag)
461 {
462     // FIXME: Implement
463 }
464
465 void TestRunner::setJavaScriptCanAccessClipboard(bool enabled)
466 {
467     COMPtr<IWebView> webView;
468     if (FAILED(frame->webView(&webView)))
469         return;
470
471     COMPtr<IWebPreferences> preferences;
472     if (FAILED(webView->preferences(&preferences)))
473         return;
474
475     COMPtr<IWebPreferencesPrivate> prefsPrivate(Query, preferences);
476     if (!prefsPrivate)
477         return;
478
479     prefsPrivate->setJavaScriptCanAccessClipboard(enabled);
480 }
481
482 void TestRunner::setTabKeyCyclesThroughElements(bool shouldCycle)
483 {
484     COMPtr<IWebView> webView;
485     if (FAILED(frame->webView(&webView)))
486         return;
487
488     COMPtr<IWebViewPrivate> viewPrivate;
489     if (FAILED(webView->QueryInterface(&viewPrivate)))
490         return;
491
492     viewPrivate->setTabKeyCyclesThroughElements(shouldCycle ? TRUE : FALSE);
493 }
494
495 void TestRunner::setUseDashboardCompatibilityMode(bool flag)
496 {
497     // FIXME: Implement!
498 }
499
500 void TestRunner::setUserStyleSheetEnabled(bool flag)
501 {
502     COMPtr<IWebView> webView;
503     if (FAILED(frame->webView(&webView)))
504         return;
505
506     COMPtr<IWebPreferences> preferences;
507     if (FAILED(webView->preferences(&preferences)))
508         return;
509
510     preferences->setUserStyleSheetEnabled(flag);
511 }
512
513 bool appendComponentToPath(wstring& path, const wstring& component)
514 {
515     WCHAR buffer[MAX_PATH];
516
517     if (path.size() + 1 > MAX_PATH)
518         return false;
519
520     memcpy(buffer, path.data(), path.size() * sizeof(WCHAR));
521     buffer[path.size()] = '\0';
522
523     if (!PathAppendW(buffer, component.c_str()))
524         return false;
525
526     path = wstring(buffer);
527     return true;
528 }
529
530 static bool followShortcuts(wstring& path)
531 {
532     if (PathFileExists(path.c_str()))
533         return true;
534
535     // Do we have a shortcut?
536     wstring linkPath = path;
537     linkPath.append(TEXT(".lnk"));
538     if (!PathFileExists(linkPath.c_str()))
539        return true;
540
541     // We have a shortcut, find its target.
542     COMPtr<IShellLink> shortcut(Create, CLSID_ShellLink);
543     if (!shortcut)
544        return false;
545     COMPtr<IPersistFile> persistFile(Query, shortcut);
546     if (!shortcut)
547         return false;
548     if (FAILED(persistFile->Load(linkPath.c_str(), STGM_READ)))
549         return false;
550     if (FAILED(shortcut->Resolve(0, 0)))
551         return false;
552     WCHAR targetPath[MAX_PATH];
553     DWORD targetPathLen = _countof(targetPath);
554     if (FAILED(shortcut->GetPath(targetPath, targetPathLen, 0, 0)))
555         return false;
556     if (!PathFileExists(targetPath))
557         return false;
558     // Use the target path as the result path instead.
559     path = wstring(targetPath);
560
561     return true;
562 }
563
564 static bool resolveCygwinPath(const wstring& cygwinPath, wstring& windowsPath)
565 {
566     wstring fileProtocol = L"file://";
567     bool isFileProtocol = cygwinPath.find(fileProtocol) != string::npos;
568     if (cygwinPath[isFileProtocol ? 7 : 0] != '/') // ensure path is absolute
569         return false;
570
571     // Get the Root path.
572     WCHAR rootPath[MAX_PATH];
573     DWORD rootPathSize = _countof(rootPath);
574     DWORD keyType;
575     DWORD result = ::SHGetValueW(HKEY_LOCAL_MACHINE, TEXT("SOFTWARE\\Cygnus Solutions\\Cygwin\\mounts v2\\/"), TEXT("native"), &keyType, &rootPath, &rootPathSize);
576
577     if (result != ERROR_SUCCESS || keyType != REG_SZ) {
578         // Cygwin 1.7 doesn't store Cygwin's root as a mount point anymore, because mount points are now stored in /etc/fstab.
579         // However, /etc/fstab doesn't contain any information about where / is located as a Windows path, so we need to use Cygwin's
580         // new registry key that has the root.
581         result = ::SHGetValueW(HKEY_LOCAL_MACHINE, TEXT("SOFTWARE\\Cygwin\\setup"), TEXT("rootdir"), &keyType, &rootPath, &rootPathSize);
582         if (result != ERROR_SUCCESS || keyType != REG_SZ)
583             return false;
584     }
585
586     windowsPath = wstring(rootPath, rootPathSize);
587
588     int oldPos = isFileProtocol ? 8 : 1;
589     while (1) {
590         int newPos = cygwinPath.find('/', oldPos);
591
592         if (newPos == -1) {
593             wstring pathComponent = cygwinPath.substr(oldPos);
594
595             if (!appendComponentToPath(windowsPath, pathComponent))
596                return false;
597
598             if (!followShortcuts(windowsPath))
599                 return false;
600
601             break;
602         }
603
604         wstring pathComponent = cygwinPath.substr(oldPos, newPos - oldPos);
605         if (!appendComponentToPath(windowsPath, pathComponent))
606             return false;
607
608         if (!followShortcuts(windowsPath))
609             return false;
610
611         oldPos = newPos + 1;
612     }
613
614     if (isFileProtocol)
615         windowsPath = fileProtocol + windowsPath;
616
617     return true;
618 }
619
620 void TestRunner::setUserStyleSheetLocation(JSStringRef jsURL)
621 {
622     COMPtr<IWebView> webView;
623     if (FAILED(frame->webView(&webView)))
624         return;
625
626     COMPtr<IWebPreferences> preferences;
627     if (FAILED(webView->preferences(&preferences)))
628         return;
629
630     RetainPtr<CFStringRef> urlString = adoptCF(JSStringCopyCFString(0, jsURL));
631     RetainPtr<CFURLRef> url = adoptCF(CFURLCreateWithString(0, urlString.get(), 0));
632     if (!url)
633         return;
634
635     // Now copy the file system path, POSIX style.
636     RetainPtr<CFStringRef> pathCF = adoptCF(CFURLCopyFileSystemPath(url.get(), kCFURLPOSIXPathStyle));
637     if (!pathCF)
638         return;
639
640     wstring path = cfStringRefToWString(pathCF.get());
641
642     wstring resultPath;
643     if (!resolveCygwinPath(path, resultPath))
644         return;
645
646     // The path has been resolved, now convert it back to a CFURL.
647     int result = WideCharToMultiByte(CP_UTF8, 0, resultPath.c_str(), resultPath.size() + 1, 0, 0, 0, 0);
648     Vector<char> utf8Vector(result);
649     result = WideCharToMultiByte(CP_UTF8, 0, resultPath.c_str(), resultPath.size() + 1, utf8Vector.data(), result, 0, 0);
650     if (!result)
651         return;
652
653     url = CFURLCreateFromFileSystemRepresentation(0, (const UInt8*)utf8Vector.data(), utf8Vector.size() - 1, false);
654     if (!url)
655         return;
656
657     resultPath = cfStringRefToWString(CFURLGetString(url.get()));
658
659     BSTR resultPathBSTR = SysAllocStringLen(resultPath.data(), resultPath.size());
660     preferences->setUserStyleSheetLocation(resultPathBSTR);
661     SysFreeString(resultPathBSTR);
662 }
663
664 void TestRunner::setValueForUser(JSContextRef context, JSValueRef element, JSStringRef value)
665 {
666     COMPtr<IWebView> webView;
667     if (FAILED(frame->webView(&webView)))
668         return;
669
670     COMPtr<IWebViewPrivate> webViewPrivate(Query, webView);
671     if (!webViewPrivate)
672         return;
673
674     COMPtr<IDOMElement> domElement;
675     if (FAILED(webViewPrivate->elementFromJS(context, element, &domElement)))
676         return;
677
678     COMPtr<IDOMHTMLInputElement> domInputElement;
679     if (FAILED(domElement->QueryInterface(IID_IDOMHTMLInputElement, reinterpret_cast<void**>(&domInputElement))))
680         return;
681
682     _bstr_t valueBSTR(JSStringCopyBSTR(value), false);
683
684     domInputElement->setValueForUser(valueBSTR);
685 }
686
687 void TestRunner::setViewModeMediaFeature(JSStringRef mode)
688 {
689     // FIXME: implement
690 }
691
692 void TestRunner::setPersistentUserStyleSheetLocation(JSStringRef jsURL)
693 {
694     RetainPtr<CFStringRef> urlString = adoptCF(JSStringCopyCFString(0, jsURL));
695     ::setPersistentUserStyleSheetLocation(urlString.get());
696 }
697
698 void TestRunner::clearPersistentUserStyleSheet()
699 {
700     ::setPersistentUserStyleSheetLocation(0);
701 }
702
703 void TestRunner::setWindowIsKey(bool flag)
704 {
705     COMPtr<IWebView> webView;
706     if (FAILED(frame->webView(&webView)))
707         return;
708
709     COMPtr<IWebViewPrivate> viewPrivate;
710     if (FAILED(webView->QueryInterface(&viewPrivate)))
711         return;
712
713     OLE_HANDLE webViewWindow;
714     if (FAILED(viewPrivate->viewWindow(&webViewWindow)))
715         return;
716
717     ::SendMessage(reinterpret_cast<HWND>(webViewWindow), flag ? WM_SETFOCUS : WM_KILLFOCUS, (WPARAM)::GetDesktopWindow(), 0);
718 }
719
720 static const CFTimeInterval waitToDumpWatchdogInterval = 30.0;
721
722 static void CALLBACK waitUntilDoneWatchdogFired(HWND, UINT, UINT_PTR, DWORD)
723 {
724     gTestRunner->waitToDumpWatchdogTimerFired();
725 }
726
727 void TestRunner::setWaitToDump(bool waitUntilDone)
728 {
729     m_waitToDump = waitUntilDone;
730     if (m_waitToDump && !waitToDumpWatchdog)
731         waitToDumpWatchdog = SetTimer(0, 0, waitToDumpWatchdogInterval * 1000, waitUntilDoneWatchdogFired);
732 }
733
734 int TestRunner::windowCount()
735 {
736     return openWindows().size();
737 }
738
739 void TestRunner::execCommand(JSStringRef name, JSStringRef value)
740 {
741     wstring wName = jsStringRefToWString(name);
742     wstring wValue = jsStringRefToWString(value);
743
744     COMPtr<IWebView> webView;
745     if (FAILED(frame->webView(&webView)))
746         return;
747
748     COMPtr<IWebViewPrivate> viewPrivate;
749     if (FAILED(webView->QueryInterface(&viewPrivate)))
750         return;
751
752     BSTR nameBSTR = SysAllocStringLen((OLECHAR*)wName.c_str(), wName.length());
753     BSTR valueBSTR = SysAllocStringLen((OLECHAR*)wValue.c_str(), wValue.length());
754     viewPrivate->executeCoreCommandByName(nameBSTR, valueBSTR);
755
756     SysFreeString(nameBSTR);
757     SysFreeString(valueBSTR);
758 }
759
760 bool TestRunner::findString(JSContextRef /* context */, JSStringRef /* target */, JSObjectRef /* optionsArray */)
761 {
762     // FIXME: Implement
763     return false;
764 }
765
766 void TestRunner::setCacheModel(int)
767 {
768     // FIXME: Implement
769 }
770
771 bool TestRunner::isCommandEnabled(JSStringRef /*name*/)
772 {
773     printf("ERROR: TestRunner::isCommandEnabled() not implemented\n");
774     return false;
775 }
776
777 void TestRunner::clearAllApplicationCaches()
778 {
779     // FIXME: Implement to support application cache quotas.
780 }
781
782 void TestRunner::clearApplicationCacheForOrigin(JSStringRef origin)
783 {
784     // FIXME: Implement to support deleting all application cache for an origin.
785 }
786
787 JSValueRef TestRunner::originsWithApplicationCache(JSContextRef context)
788 {
789     // FIXME: Implement to get origins that have application caches.
790     return JSValueMakeUndefined(context);
791 }
792
793 long long TestRunner::applicationCacheDiskUsageForOrigin(JSStringRef name)
794 {
795     // FIXME: Implement to get disk usage by all application caches for an origin.
796     return 0;
797 }
798
799 void TestRunner::clearAllDatabases()
800 {
801     COMPtr<IWebDatabaseManager> databaseManager;
802     COMPtr<IWebDatabaseManager> tmpDatabaseManager;
803     if (FAILED(WebKitCreateInstance(CLSID_WebDatabaseManager, 0, IID_IWebDatabaseManager, (void**)&tmpDatabaseManager)))
804         return;
805     if (FAILED(tmpDatabaseManager->sharedWebDatabaseManager(&databaseManager)))
806         return;
807
808     databaseManager->deleteAllDatabases();
809 }
810
811 void TestRunner::overridePreference(JSStringRef key, JSStringRef value)
812 {
813     COMPtr<IWebView> webView;
814     if (FAILED(frame->webView(&webView)))
815         return;
816
817     COMPtr<IWebPreferences> preferences;
818     if (FAILED(webView->preferences(&preferences)))
819         return;
820
821     COMPtr<IWebPreferencesPrivate> prefsPrivate(Query, preferences);
822     if (!prefsPrivate)
823         return;
824
825     BSTR keyBSTR = JSStringCopyBSTR(key);
826     BSTR valueBSTR = JSStringCopyBSTR(value);
827     prefsPrivate->setPreferenceForTest(keyBSTR, valueBSTR);
828     SysFreeString(keyBSTR);
829     SysFreeString(valueBSTR);
830 }
831
832 void TestRunner::setDatabaseQuota(unsigned long long quota)
833 {
834     COMPtr<IWebDatabaseManager> databaseManager;
835     COMPtr<IWebDatabaseManager> tmpDatabaseManager;
836
837     if (FAILED(WebKitCreateInstance(CLSID_WebDatabaseManager, 0, IID_IWebDatabaseManager, (void**)&tmpDatabaseManager)))
838         return;
839     if (FAILED(tmpDatabaseManager->sharedWebDatabaseManager(&databaseManager)))
840         return;
841
842     databaseManager->setQuota(TEXT("file:///"), quota);
843 }
844
845 void TestRunner::goBack()
846 {
847     // FIXME: implement to enable loader/navigation-while-deferring-loads.html
848 }
849
850 void TestRunner::setDefersLoading(bool)
851 {
852     // FIXME: implement to enable loader/navigation-while-deferring-loads.html
853 }
854
855 void TestRunner::setDomainRelaxationForbiddenForURLScheme(bool forbidden, JSStringRef scheme)
856 {
857     COMPtr<IWebViewPrivate> webView;
858     if (FAILED(WebKitCreateInstance(__uuidof(WebView), 0, __uuidof(webView), reinterpret_cast<void**>(&webView))))
859         return;
860
861     BSTR schemeBSTR = JSStringCopyBSTR(scheme);
862     webView->setDomainRelaxationForbiddenForURLScheme(forbidden, schemeBSTR);
863     SysFreeString(schemeBSTR);
864 }
865
866 void TestRunner::setAppCacheMaximumSize(unsigned long long size)
867 {
868     printf("ERROR: TestRunner::setAppCacheMaximumSize() not implemented\n");
869 }
870
871 static _bstr_t bstrT(JSStringRef jsString)
872 {
873     // The false parameter tells the _bstr_t constructor to adopt the BSTR we pass it.
874     return _bstr_t(JSStringCopyBSTR(jsString), false);
875 }
876
877 void TestRunner::addOriginAccessWhitelistEntry(JSStringRef sourceOrigin, JSStringRef destinationProtocol, JSStringRef destinationHost, bool allowDestinationSubdomains)
878 {
879     COMPtr<IWebViewPrivate> webView;
880     if (FAILED(WebKitCreateInstance(__uuidof(WebView), 0, __uuidof(webView), reinterpret_cast<void**>(&webView))))
881         return;
882
883     webView->addOriginAccessWhitelistEntry(bstrT(sourceOrigin).GetBSTR(), bstrT(destinationProtocol).GetBSTR(), bstrT(destinationHost).GetBSTR(), allowDestinationSubdomains);
884 }
885
886 void TestRunner::removeOriginAccessWhitelistEntry(JSStringRef sourceOrigin, JSStringRef destinationProtocol, JSStringRef destinationHost, bool allowDestinationSubdomains)
887 {
888     COMPtr<IWebViewPrivate> webView;
889     if (FAILED(WebKitCreateInstance(__uuidof(WebView), 0, __uuidof(webView), reinterpret_cast<void**>(&webView))))
890         return;
891
892     webView->removeOriginAccessWhitelistEntry(bstrT(sourceOrigin).GetBSTR(), bstrT(destinationProtocol).GetBSTR(), bstrT(destinationHost).GetBSTR(), allowDestinationSubdomains);
893 }
894
895 void TestRunner::setScrollbarPolicy(JSStringRef orientation, JSStringRef policy)
896 {
897     // FIXME: implement
898 }
899
900 void TestRunner::addUserScript(JSStringRef source, bool runAtStart, bool allFrames)
901 {
902     COMPtr<IWebViewPrivate> webView;
903     if (FAILED(WebKitCreateInstance(__uuidof(WebView), 0, __uuidof(webView), reinterpret_cast<void**>(&webView))))
904         return;
905
906     COMPtr<IWebScriptWorld> world;
907     if (FAILED(WebKitCreateInstance(__uuidof(WebScriptWorld), 0, __uuidof(world), reinterpret_cast<void**>(&world))))
908         return;
909
910     webView->addUserScriptToGroup(_bstr_t(L"org.webkit.DumpRenderTree").GetBSTR(), world.get(), bstrT(source).GetBSTR(), 0, 0, 0, 0, 0, runAtStart ? WebInjectAtDocumentStart : WebInjectAtDocumentEnd);
911 }
912
913
914 void TestRunner::addUserStyleSheet(JSStringRef source, bool allFrames)
915 {
916     COMPtr<IWebViewPrivate> webView;
917     if (FAILED(WebKitCreateInstance(__uuidof(WebView), 0, __uuidof(webView), reinterpret_cast<void**>(&webView))))
918         return;
919
920     COMPtr<IWebScriptWorld> world;
921     if (FAILED(WebKitCreateInstance(__uuidof(WebScriptWorld), 0, __uuidof(world), reinterpret_cast<void**>(&world))))
922         return;
923
924     webView->addUserStyleSheetToGroup(_bstr_t(L"org.webkit.DumpRenderTree").GetBSTR(), world.get(), bstrT(source).GetBSTR(), 0, 0, 0, 0, 0);
925 }
926
927 void TestRunner::setDeveloperExtrasEnabled(bool enabled)
928 {
929     COMPtr<IWebView> webView;
930     if (FAILED(frame->webView(&webView)))
931         return;
932
933     COMPtr<IWebPreferences> preferences;
934     if (FAILED(webView->preferences(&preferences)))
935         return;
936
937     COMPtr<IWebPreferencesPrivate> prefsPrivate(Query, preferences);
938     if (!prefsPrivate)
939         return;
940
941     prefsPrivate->setDeveloperExtrasEnabled(enabled);
942 }
943
944 void TestRunner::showWebInspector()
945 {
946     COMPtr<IWebView> webView;
947     if (FAILED(frame->webView(&webView)))
948         return;
949
950     COMPtr<IWebViewPrivate> viewPrivate(Query, webView);
951     if (!viewPrivate)
952         return;
953
954     COMPtr<IWebInspector> inspector;
955     if (SUCCEEDED(viewPrivate->inspector(&inspector)))
956         inspector->show();
957 }
958
959 void TestRunner::closeWebInspector()
960 {
961     COMPtr<IWebView> webView;
962     if (FAILED(frame->webView(&webView)))
963         return;
964
965     COMPtr<IWebViewPrivate> viewPrivate(Query, webView);
966     if (!viewPrivate)
967         return;
968
969     COMPtr<IWebInspector> inspector;
970     if (FAILED(viewPrivate->inspector(&inspector)))
971         return;
972
973     inspector->close();
974 }
975
976 void TestRunner::evaluateInWebInspector(JSStringRef script)
977 {
978     COMPtr<IWebView> webView;
979     if (FAILED(frame->webView(&webView)))
980         return;
981
982     COMPtr<IWebViewPrivate> viewPrivate(Query, webView);
983     if (!viewPrivate)
984         return;
985
986     COMPtr<IWebInspector> inspector;
987     if (FAILED(viewPrivate->inspector(&inspector)))
988         return;
989
990     COMPtr<IWebInspectorPrivate> inspectorPrivate(Query, inspector);
991     if (!inspectorPrivate)
992         return;
993
994     inspectorPrivate->evaluateInFrontend(bstrT(script).GetBSTR());
995 }
996
997 typedef HashMap<unsigned, COMPtr<IWebScriptWorld> > WorldMap;
998 static WorldMap& worldMap()
999 {
1000     static WorldMap& map = *new WorldMap;
1001     return map;
1002 }
1003
1004 unsigned worldIDForWorld(IWebScriptWorld* world)
1005 {
1006     WorldMap::const_iterator end = worldMap().end();
1007     for (WorldMap::const_iterator it = worldMap().begin(); it != end; ++it) {
1008         if (it->value == world)
1009             return it->key;
1010     }
1011
1012     return 0;
1013 }
1014
1015 void TestRunner::evaluateScriptInIsolatedWorldAndReturnValue(unsigned worldID, JSObjectRef globalObject, JSStringRef script)
1016 {
1017     // FIXME: Implement this.
1018 }
1019
1020 void TestRunner::evaluateScriptInIsolatedWorld(unsigned worldID, JSObjectRef globalObject, JSStringRef script)
1021 {
1022     COMPtr<IWebFramePrivate> framePrivate(Query, frame);
1023     if (!framePrivate)
1024         return;
1025
1026     // A worldID of 0 always corresponds to a new world. Any other worldID corresponds to a world
1027     // that is created once and cached forever.
1028     COMPtr<IWebScriptWorld> world;
1029     if (!worldID) {
1030         if (FAILED(WebKitCreateInstance(__uuidof(WebScriptWorld), 0, __uuidof(world), reinterpret_cast<void**>(&world))))
1031             return;
1032     } else {
1033         COMPtr<IWebScriptWorld>& worldSlot = worldMap().add(worldID, nullptr).iterator->value;
1034         if (!worldSlot && FAILED(WebKitCreateInstance(__uuidof(WebScriptWorld), 0, __uuidof(worldSlot), reinterpret_cast<void**>(&worldSlot))))
1035             return;
1036         world = worldSlot;
1037     }
1038
1039     BSTR result;
1040     if (FAILED(framePrivate->stringByEvaluatingJavaScriptInScriptWorld(world.get(), globalObject, bstrT(script).GetBSTR(), &result)))
1041         return;
1042     SysFreeString(result);
1043 }
1044
1045 void TestRunner::removeAllVisitedLinks()
1046 {
1047     COMPtr<IWebHistory> history;
1048     if (FAILED(WebKitCreateInstance(CLSID_WebHistory, 0, __uuidof(history), reinterpret_cast<void**>(&history))))
1049         return;
1050
1051     COMPtr<IWebHistory> sharedHistory;
1052     if (FAILED(history->optionalSharedHistory(&sharedHistory)) || !sharedHistory)
1053         return;
1054
1055     COMPtr<IWebHistoryPrivate> sharedHistoryPrivate;
1056     if (FAILED(sharedHistory->QueryInterface(&sharedHistoryPrivate)))
1057         return;
1058
1059     sharedHistoryPrivate->removeAllVisitedLinks();
1060 }
1061
1062 void TestRunner::apiTestNewWindowDataLoadBaseURL(JSStringRef utf8Data, JSStringRef baseURL)
1063 {
1064
1065 }
1066
1067 void TestRunner::apiTestGoToCurrentBackForwardItem()
1068 {
1069     COMPtr<IWebView> webView;
1070     if (FAILED(frame->webView(&webView)))
1071         return;
1072
1073     COMPtr<IWebBackForwardList> backForwardList;
1074     if (FAILED(webView->backForwardList(&backForwardList)))
1075         return;
1076
1077     COMPtr<IWebHistoryItem> item;
1078     if (FAILED(backForwardList->currentItem(&item)))
1079         return;
1080
1081     BOOL success;
1082     webView->goToBackForwardItem(item.get(), &success);
1083 }
1084
1085 void TestRunner::setWebViewEditable(bool)
1086 {
1087 }
1088
1089 void TestRunner::authenticateSession(JSStringRef, JSStringRef, JSStringRef)
1090 {
1091 }
1092
1093 void TestRunner::abortModal()
1094 {
1095 }
1096
1097 void TestRunner::setSerializeHTTPLoads(bool)
1098 {
1099     // FIXME: Implement.
1100 }
1101
1102 void TestRunner::syncLocalStorage()
1103 {
1104     // FIXME: Implement.
1105 }
1106
1107 void TestRunner::observeStorageTrackerNotifications(unsigned number)
1108 {
1109     // FIXME: Implement.
1110 }
1111
1112 void TestRunner::deleteAllLocalStorage()
1113 {
1114     // FIXME: Implement.
1115 }
1116
1117 JSValueRef TestRunner::originsWithLocalStorage(JSContextRef context)
1118 {
1119     // FIXME: Implement.
1120     return JSValueMakeUndefined(context);
1121 }
1122
1123 long long TestRunner::localStorageDiskUsageForOrigin(JSStringRef originIdentifier)
1124 {
1125     // FIXME: Implement to support getting local storage disk usage for an origin.
1126     return 0;
1127 }
1128
1129 void TestRunner::deleteLocalStorageForOrigin(JSStringRef URL)
1130 {
1131     // FIXME: Implement.
1132 }
1133
1134 void TestRunner::setTextDirection(JSStringRef direction)
1135 {
1136     COMPtr<IWebFramePrivate> framePrivate(Query, frame);
1137     if (!framePrivate)
1138         return;
1139
1140     framePrivate->setTextDirection(bstrT(direction).GetBSTR());
1141 }
1142
1143 void TestRunner::addChromeInputField()
1144 {
1145 }
1146
1147 void TestRunner::removeChromeInputField()
1148 {
1149 }
1150
1151 void TestRunner::focusWebView()
1152 {
1153 }
1154
1155 void TestRunner::setBackingScaleFactor(double)
1156 {
1157 }
1158
1159 void TestRunner::grantWebNotificationPermission(JSStringRef origin)
1160 {
1161 }
1162
1163 void TestRunner::denyWebNotificationPermission(JSStringRef jsOrigin)
1164 {
1165 }
1166
1167 void TestRunner::removeAllWebNotificationPermissions()
1168 {
1169 }
1170
1171 void TestRunner::simulateWebNotificationClick(JSValueRef jsNotification)
1172 {
1173 }
1174
1175 void TestRunner::simulateLegacyWebNotificationClick(JSStringRef title)
1176 {
1177     // FIXME: Implement.
1178 }
1179
1180 void TestRunner::resetPageVisibility()
1181 {
1182     // FIXME: Implement this.
1183 }
1184
1185 void TestRunner::setPageVisibility(const char*)
1186 {
1187     // FIXME: Implement this.
1188 }
1189
1190 void TestRunner::setAutomaticLinkDetectionEnabled(bool)
1191 {
1192     // FIXME: Implement this.
1193 }
1194
1195 void TestRunner::setStorageDatabaseIdleInterval(double)
1196 {
1197     // FIXME: Implement this.
1198 }
1199
1200 void TestRunner::closeIdleLocalStorageDatabases()
1201 {
1202     // FIXME: Implement this.
1203 }