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