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