1/*
2 * Copyright (C) 2006, 2007, 2008, 2009, 2010 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 "LayoutTestController.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/Assertions.h>
39#include <JavaScriptCore/JSRetainPtr.h>
40#include <JavaScriptCore/JSStringRefBSTR.h>
41#include <JavaScriptCore/JavaScriptCore.h>
42#include <WebCore/COMPtr.h>
43#include <WebKit/WebKit.h>
44#include <WebKit/WebKitCOMAPI.h>
45#include <comutil.h>
46#include <shlwapi.h>
47#include <shlguid.h>
48#include <shobjidl.h>
49#include <string>
50#include <wtf/Platform.h>
51#include <wtf/RetainPtr.h>
52#include <wtf/Vector.h>
53
54using std::string;
55using std::wstring;
56
57static bool resolveCygwinPath(const wstring& cygwinPath, wstring& windowsPath);
58
59LayoutTestController::~LayoutTestController()
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
82void LayoutTestController::addDisallowedURL(JSStringRef url)
83{
84    // FIXME: Implement!
85}
86
87void LayoutTestController::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
113bool LayoutTestController::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
128JSStringRef LayoutTestController::copyDecodedHostName(JSStringRef name)
129{
130    // FIXME: Implement!
131    return 0;
132}
133
134JSStringRef LayoutTestController::copyEncodedHostName(JSStringRef name)
135{
136    // FIXME: Implement!
137    return 0;
138}
139
140void LayoutTestController::disableImageLoading()
141{
142    COMPtr<IWebView> webView;
143    if (FAILED(frame->webView(&webView)))
144        return;
145
146    COMPtr<IWebPreferences> preferences;
147    if (FAILED(webView->preferences(&preferences)))
148        return;
149
150    preferences->setLoadsImagesAutomatically(FALSE);
151}
152
153void LayoutTestController::dispatchPendingLoadRequests()
154{
155    // FIXME: Implement for testing fix for 6727495
156}
157
158void LayoutTestController::display()
159{
160    displayWebView();
161}
162
163void LayoutTestController::keepWebHistory()
164{
165    COMPtr<IWebHistory> history;
166    if (FAILED(WebKitCreateInstance(CLSID_WebHistory, 0, __uuidof(history), reinterpret_cast<void**>(&history))))
167        return;
168
169    COMPtr<IWebHistory> sharedHistory;
170    if (FAILED(WebKitCreateInstance(CLSID_WebHistory, 0, __uuidof(sharedHistory), reinterpret_cast<void**>(&sharedHistory))))
171        return;
172
173    history->setOptionalSharedHistory(sharedHistory.get());
174}
175
176JSValueRef LayoutTestController::computedStyleIncludingVisitedInfo(JSContextRef context, JSValueRef value)
177{
178    // FIXME: Implement this.
179    return JSValueMakeUndefined(context);
180}
181
182JSValueRef LayoutTestController::nodesFromRect(JSContextRef context, JSValueRef value, int x, int y, unsigned top, unsigned right, unsigned bottom, unsigned left, bool ignoreClipping)
183{
184    // FIXME: Implement this.
185    return JSValueMakeUndefined(context);
186}
187
188JSRetainPtr<JSStringRef> LayoutTestController::layerTreeAsText() const
189{
190    COMPtr<IWebFramePrivate> framePrivate(Query, frame);
191    if (!framePrivate)
192        return false;
193
194    BSTR textBSTR = 0;
195    HRESULT hr = framePrivate->layerTreeAsText(&textBSTR);
196
197    wstring text(textBSTR, SysStringLen(textBSTR));
198    SysFreeString(textBSTR);
199    JSRetainPtr<JSStringRef> textValueJS(Adopt, JSStringCreateWithCharacters(text.data(), text.length()));
200    return textValueJS;
201}
202
203JSRetainPtr<JSStringRef> LayoutTestController::markerTextForListItem(JSContextRef context, JSValueRef nodeObject) const
204{
205    COMPtr<IWebView> webView;
206    if (FAILED(frame->webView(&webView)))
207        return 0;
208
209    COMPtr<IWebViewPrivate> webViewPrivate(Query, webView);
210    if (!webViewPrivate)
211        return 0;
212
213    COMPtr<IDOMElement> element;
214    if (FAILED(webViewPrivate->elementFromJS(context, nodeObject, &element)))
215        return 0;
216
217    COMPtr<IDOMElementPrivate> elementPrivate(Query, element);
218    if (!elementPrivate)
219        return 0;
220
221    BSTR textBSTR = 0;
222    if (FAILED(elementPrivate->markerTextForListItem(&textBSTR)))
223        return 0;
224
225    JSRetainPtr<JSStringRef> markerText(Adopt, JSStringCreateWithBSTR(textBSTR));
226    SysFreeString(textBSTR);
227    return markerText;
228}
229
230void LayoutTestController::waitForPolicyDelegate()
231{
232    COMPtr<IWebView> webView;
233    if (FAILED(frame->webView(&webView)))
234        return;
235
236    setWaitToDump(true);
237    policyDelegate->setControllerToNotifyDone(this);
238    webView->setPolicyDelegate(policyDelegate);
239}
240
241size_t LayoutTestController::webHistoryItemCount()
242{
243    COMPtr<IWebHistory> history;
244    if (FAILED(WebKitCreateInstance(CLSID_WebHistory, 0, __uuidof(history), reinterpret_cast<void**>(&history))))
245        return 0;
246
247    COMPtr<IWebHistory> sharedHistory;
248    if (FAILED(history->optionalSharedHistory(&sharedHistory)) || !sharedHistory)
249        return 0;
250
251    COMPtr<IWebHistoryPrivate> sharedHistoryPrivate;
252    if (FAILED(sharedHistory->QueryInterface(&sharedHistoryPrivate)))
253        return 0;
254
255    int count;
256    if (FAILED(sharedHistoryPrivate->allItems(&count, 0)))
257        return 0;
258
259    return count;
260}
261
262unsigned LayoutTestController::workerThreadCount() const
263{
264    COMPtr<IWebWorkersPrivate> workers;
265    if (FAILED(WebKitCreateInstance(CLSID_WebWorkersPrivate, 0, __uuidof(workers), reinterpret_cast<void**>(&workers))))
266        return 0;
267    unsigned count;
268    if (FAILED(workers->workerThreadCount(&count)))
269        return 0;
270    return count;
271}
272
273void LayoutTestController::notifyDone()
274{
275    // Same as on mac.  This can be shared.
276    if (m_waitToDump && !topLoadingFrame && !WorkQueue::shared()->count())
277        dump();
278    m_waitToDump = false;
279}
280
281JSStringRef LayoutTestController::pathToLocalResource(JSContextRef context, JSStringRef url)
282{
283    wstring input(JSStringGetCharactersPtr(url), JSStringGetLength(url));
284
285    wstring localPath;
286    if (!resolveCygwinPath(input, localPath)) {
287        printf("ERROR: Failed to resolve Cygwin path %S\n", input.c_str());
288        return 0;
289    }
290
291    return JSStringCreateWithCharacters(localPath.c_str(), localPath.length());
292}
293
294static wstring jsStringRefToWString(JSStringRef jsStr)
295{
296    size_t length = JSStringGetLength(jsStr);
297    Vector<WCHAR> buffer(length + 1);
298    memcpy(buffer.data(), JSStringGetCharactersPtr(jsStr), length * sizeof(WCHAR));
299    buffer[length] = '\0';
300
301    return buffer.data();
302}
303
304void LayoutTestController::queueLoad(JSStringRef url, JSStringRef target)
305{
306    COMPtr<IWebDataSource> dataSource;
307    if (FAILED(frame->dataSource(&dataSource)))
308        return;
309
310    COMPtr<IWebURLResponse> response;
311    if (FAILED(dataSource->response(&response)) || !response)
312        return;
313
314    BSTR responseURLBSTR;
315    if (FAILED(response->URL(&responseURLBSTR)))
316        return;
317    wstring responseURL(responseURLBSTR, SysStringLen(responseURLBSTR));
318    SysFreeString(responseURLBSTR);
319
320    // FIXME: We should do real relative URL resolution here.
321    int lastSlash = responseURL.rfind('/');
322    if (lastSlash != -1)
323        responseURL = responseURL.substr(0, lastSlash);
324
325    wstring wURL = jsStringRefToWString(url);
326    wstring wAbsoluteURL = responseURL + TEXT("/") + wURL;
327    JSRetainPtr<JSStringRef> jsAbsoluteURL(Adopt, JSStringCreateWithCharacters(wAbsoluteURL.data(), wAbsoluteURL.length()));
328
329    WorkQueue::shared()->queue(new LoadItem(jsAbsoluteURL.get(), target));
330}
331
332void LayoutTestController::setAcceptsEditing(bool acceptsEditing)
333{
334    COMPtr<IWebView> webView;
335    if (FAILED(frame->webView(&webView)))
336        return;
337
338    COMPtr<IWebViewEditing> viewEditing;
339    if (FAILED(webView->QueryInterface(&viewEditing)))
340        return;
341
342    COMPtr<IWebEditingDelegate> delegate;
343    if (FAILED(viewEditing->editingDelegate(&delegate)))
344        return;
345
346    EditingDelegate* editingDelegate = (EditingDelegate*)(IWebEditingDelegate*)delegate.get();
347    editingDelegate->setAcceptsEditing(acceptsEditing);
348}
349
350void LayoutTestController::setAlwaysAcceptCookies(bool alwaysAcceptCookies)
351{
352    if (alwaysAcceptCookies == m_alwaysAcceptCookies)
353        return;
354
355    if (!::setAlwaysAcceptCookies(alwaysAcceptCookies))
356        return;
357    m_alwaysAcceptCookies = alwaysAcceptCookies;
358}
359
360void LayoutTestController::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
377void LayoutTestController::setAutofilled(JSContextRef context, JSValueRef nodeObject, bool autofilled)
378{
379    COMPtr<IWebView> webView;
380    if (FAILED(frame->webView(&webView)))
381        return;
382
383    COMPtr<IWebViewPrivate> webViewPrivate(Query, webView);
384    if (!webViewPrivate)
385        return;
386
387    COMPtr<IDOMElement> element;
388    if (FAILED(webViewPrivate->elementFromJS(context, nodeObject, &element)))
389        return;
390
391    COMPtr<IFormsAutoFillTransition> autofillElement(Query, element);
392    if (!autofillElement)
393        return;
394
395    autofillElement->setAutofilled(autofilled);
396}
397
398void LayoutTestController::setCustomPolicyDelegate(bool setDelegate, bool permissive)
399{
400    COMPtr<IWebView> webView;
401    if (FAILED(frame->webView(&webView)))
402        return;
403
404    if (setDelegate) {
405        policyDelegate->setPermissive(permissive);
406        webView->setPolicyDelegate(policyDelegate);
407    } else
408        webView->setPolicyDelegate(0);
409}
410
411void LayoutTestController::setMockDeviceOrientation(bool canProvideAlpha, double alpha, bool canProvideBeta, double beta, bool canProvideGamma, double gamma)
412{
413    // FIXME: Implement for DeviceOrientation layout tests.
414    // See https://bugs.webkit.org/show_bug.cgi?id=30335.
415}
416
417void LayoutTestController::setMockGeolocationPosition(double latitude, double longitude, double accuracy)
418{
419    // FIXME: Implement for Geolocation layout tests.
420    // See https://bugs.webkit.org/show_bug.cgi?id=28264.
421}
422
423void LayoutTestController::setMockGeolocationError(int code, JSStringRef message)
424{
425    // FIXME: Implement for Geolocation layout tests.
426    // See https://bugs.webkit.org/show_bug.cgi?id=28264.
427}
428
429void LayoutTestController::setGeolocationPermission(bool allow)
430{
431    // FIXME: Implement for Geolocation layout tests.
432    setGeolocationPermissionCommon(allow);
433}
434
435int LayoutTestController::numberOfPendingGeolocationPermissionRequests()
436{
437    // FIXME: Implement for Geolocation layout tests.
438    return -1;
439}
440
441void LayoutTestController::addMockSpeechInputResult(JSStringRef result, double confidence, JSStringRef language)
442{
443    // FIXME: Implement for speech input layout tests.
444    // See https://bugs.webkit.org/show_bug.cgi?id=39485.
445}
446
447void LayoutTestController::setIconDatabaseEnabled(bool iconDatabaseEnabled)
448{
449    // See also <rdar://problem/6480108>
450    COMPtr<IWebIconDatabase> iconDatabase;
451    COMPtr<IWebIconDatabase> tmpIconDatabase;
452    if (FAILED(WebKitCreateInstance(CLSID_WebIconDatabase, 0, IID_IWebIconDatabase, (void**)&tmpIconDatabase)))
453        return;
454    if (FAILED(tmpIconDatabase->sharedIconDatabase(&iconDatabase)))
455        return;
456
457    iconDatabase->setEnabled(iconDatabaseEnabled);
458}
459
460void LayoutTestController::setMainFrameIsFirstResponder(bool flag)
461{
462    // FIXME: Implement!
463}
464
465void LayoutTestController::setPrivateBrowsingEnabled(bool privateBrowsingEnabled)
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    preferences->setPrivateBrowsingEnabled(privateBrowsingEnabled);
476}
477
478void LayoutTestController::setXSSAuditorEnabled(bool enabled)
479{
480    COMPtr<IWebView> webView;
481    if (FAILED(frame->webView(&webView)))
482        return;
483
484    COMPtr<IWebPreferences> preferences;
485    if (FAILED(webView->preferences(&preferences)))
486        return;
487
488    COMPtr<IWebPreferencesPrivate> prefsPrivate(Query, preferences);
489    if (!prefsPrivate)
490        return;
491
492    prefsPrivate->setXSSAuditorEnabled(enabled);
493}
494
495void LayoutTestController::setFrameFlatteningEnabled(bool enabled)
496{
497    COMPtr<IWebView> webView;
498    if (FAILED(frame->webView(&webView)))
499        return;
500
501    COMPtr<IWebPreferences> preferences;
502    if (FAILED(webView->preferences(&preferences)))
503        return;
504
505    COMPtr<IWebPreferencesPrivate> prefsPrivate(Query, preferences);
506    if (!prefsPrivate)
507        return;
508
509    prefsPrivate->setFrameFlatteningEnabled(enabled);
510}
511
512void LayoutTestController::setSpatialNavigationEnabled(bool enabled)
513{
514    // FIXME: Implement for SpatialNavigation layout tests.
515}
516
517void LayoutTestController::setAllowUniversalAccessFromFileURLs(bool enabled)
518{
519    COMPtr<IWebView> webView;
520    if (FAILED(frame->webView(&webView)))
521        return;
522
523    COMPtr<IWebPreferences> preferences;
524    if (FAILED(webView->preferences(&preferences)))
525        return;
526
527    COMPtr<IWebPreferencesPrivate> prefsPrivate(Query, preferences);
528    if (!prefsPrivate)
529        return;
530
531    prefsPrivate->setAllowUniversalAccessFromFileURLs(enabled);
532}
533
534void LayoutTestController::setAllowFileAccessFromFileURLs(bool enabled)
535{
536    COMPtr<IWebView> webView;
537    if (FAILED(frame->webView(&webView)))
538        return;
539
540    COMPtr<IWebPreferences> preferences;
541    if (FAILED(webView->preferences(&preferences)))
542        return;
543
544    COMPtr<IWebPreferencesPrivate> prefsPrivate(Query, preferences);
545    if (!prefsPrivate)
546        return;
547
548    prefsPrivate->setAllowFileAccessFromFileURLs(enabled);
549}
550
551void LayoutTestController::setPopupBlockingEnabled(bool enabled)
552{
553    COMPtr<IWebView> webView;
554    if (FAILED(frame->webView(&webView)))
555        return;
556
557    COMPtr<IWebPreferences> preferences;
558    if (FAILED(webView->preferences(&preferences)))
559        return;
560
561    preferences->setJavaScriptCanOpenWindowsAutomatically(!enabled);
562}
563
564void LayoutTestController::setPluginsEnabled(bool flag)
565{
566    // FIXME: Implement
567}
568
569void LayoutTestController::setJavaScriptCanAccessClipboard(bool enabled)
570{
571    COMPtr<IWebView> webView;
572    if (FAILED(frame->webView(&webView)))
573        return;
574
575    COMPtr<IWebPreferences> preferences;
576    if (FAILED(webView->preferences(&preferences)))
577        return;
578
579    COMPtr<IWebPreferencesPrivate> prefsPrivate(Query, preferences);
580    if (!prefsPrivate)
581        return;
582
583    prefsPrivate->setJavaScriptCanAccessClipboard(enabled);
584}
585
586void LayoutTestController::setTabKeyCyclesThroughElements(bool shouldCycle)
587{
588    COMPtr<IWebView> webView;
589    if (FAILED(frame->webView(&webView)))
590        return;
591
592    COMPtr<IWebViewPrivate> viewPrivate;
593    if (FAILED(webView->QueryInterface(&viewPrivate)))
594        return;
595
596    viewPrivate->setTabKeyCyclesThroughElements(shouldCycle ? TRUE : FALSE);
597}
598
599void LayoutTestController::setTimelineProfilingEnabled(bool flag)
600{
601    COMPtr<IWebView> webView;
602    if (FAILED(frame->webView(&webView)))
603        return;
604
605    COMPtr<IWebViewPrivate> viewPrivate;
606    if (FAILED(webView->QueryInterface(&viewPrivate)))
607        return;
608
609    COMPtr<IWebInspector> inspector;
610    if (FAILED(viewPrivate->inspector(&inspector)))
611        return;
612
613    inspector->setTimelineProfilingEnabled(flag);
614}
615
616void LayoutTestController::setUseDashboardCompatibilityMode(bool flag)
617{
618    // FIXME: Implement!
619}
620
621void LayoutTestController::setUserStyleSheetEnabled(bool flag)
622{
623    COMPtr<IWebView> webView;
624    if (FAILED(frame->webView(&webView)))
625        return;
626
627    COMPtr<IWebPreferences> preferences;
628    if (FAILED(webView->preferences(&preferences)))
629        return;
630
631   preferences->setUserStyleSheetEnabled(flag);
632}
633
634bool appendComponentToPath(wstring& path, const wstring& component)
635{
636    WCHAR buffer[MAX_PATH];
637
638    if (path.size() + 1 > MAX_PATH)
639        return false;
640
641    memcpy(buffer, path.data(), path.size() * sizeof(WCHAR));
642    buffer[path.size()] = '\0';
643
644    if (!PathAppendW(buffer, component.c_str()))
645        return false;
646
647    path = wstring(buffer);
648    return true;
649}
650
651static bool followShortcuts(wstring& path)
652{
653    if (PathFileExists(path.c_str()))
654        return true;
655
656    // Do we have a shortcut?
657    wstring linkPath = path;
658    linkPath.append(TEXT(".lnk"));
659    if (!PathFileExists(linkPath.c_str()))
660       return true;
661
662    // We have a shortcut, find its target.
663    COMPtr<IShellLink> shortcut(Create, CLSID_ShellLink);
664    if (!shortcut)
665       return false;
666    COMPtr<IPersistFile> persistFile(Query, shortcut);
667    if (!shortcut)
668        return false;
669    if (FAILED(persistFile->Load(linkPath.c_str(), STGM_READ)))
670        return false;
671    if (FAILED(shortcut->Resolve(0, 0)))
672        return false;
673    WCHAR targetPath[MAX_PATH];
674    DWORD targetPathLen = _countof(targetPath);
675    if (FAILED(shortcut->GetPath(targetPath, targetPathLen, 0, 0)))
676        return false;
677    if (!PathFileExists(targetPath))
678        return false;
679    // Use the target path as the result path instead.
680    path = wstring(targetPath);
681
682    return true;
683}
684
685static bool resolveCygwinPath(const wstring& cygwinPath, wstring& windowsPath)
686{
687    wstring fileProtocol = L"file://";
688    bool isFileProtocol = cygwinPath.find(fileProtocol) != string::npos;
689    if (cygwinPath[isFileProtocol ? 7 : 0] != '/')  // ensure path is absolute
690        return false;
691
692    // Get the Root path.
693    WCHAR rootPath[MAX_PATH];
694    DWORD rootPathSize = _countof(rootPath);
695    DWORD keyType;
696    DWORD result = ::SHGetValueW(HKEY_LOCAL_MACHINE, TEXT("SOFTWARE\\Cygnus Solutions\\Cygwin\\mounts v2\\/"), TEXT("native"), &keyType, &rootPath, &rootPathSize);
697
698    if (result != ERROR_SUCCESS || keyType != REG_SZ) {
699        // Cygwin 1.7 doesn't store Cygwin's root as a mount point anymore, because mount points are now stored in /etc/fstab.
700        // However, /etc/fstab doesn't contain any information about where / is located as a Windows path, so we need to use Cygwin's
701        // new registry key that has the root.
702        result = ::SHGetValueW(HKEY_LOCAL_MACHINE, TEXT("SOFTWARE\\Cygwin\\setup"), TEXT("rootdir"), &keyType, &rootPath, &rootPathSize);
703        if (result != ERROR_SUCCESS || keyType != REG_SZ)
704            return false;
705    }
706
707    windowsPath = wstring(rootPath, rootPathSize);
708
709    int oldPos = isFileProtocol ? 8 : 1;
710    while (1) {
711        int newPos = cygwinPath.find('/', oldPos);
712
713        if (newPos == -1) {
714            wstring pathComponent = cygwinPath.substr(oldPos);
715
716            if (!appendComponentToPath(windowsPath, pathComponent))
717               return false;
718
719            if (!followShortcuts(windowsPath))
720                return false;
721
722            break;
723        }
724
725        wstring pathComponent = cygwinPath.substr(oldPos, newPos - oldPos);
726        if (!appendComponentToPath(windowsPath, pathComponent))
727            return false;
728
729        if (!followShortcuts(windowsPath))
730            return false;
731
732        oldPos = newPos + 1;
733    }
734
735    if (isFileProtocol)
736        windowsPath = fileProtocol + windowsPath;
737
738    return true;
739}
740
741void LayoutTestController::setUserStyleSheetLocation(JSStringRef jsURL)
742{
743    COMPtr<IWebView> webView;
744    if (FAILED(frame->webView(&webView)))
745        return;
746
747    COMPtr<IWebPreferences> preferences;
748    if (FAILED(webView->preferences(&preferences)))
749        return;
750
751    RetainPtr<CFStringRef> urlString(AdoptCF, JSStringCopyCFString(0, jsURL));
752    RetainPtr<CFURLRef> url(AdoptCF, CFURLCreateWithString(0, urlString.get(), 0));
753    if (!url)
754        return;
755
756    // Now copy the file system path, POSIX style.
757    RetainPtr<CFStringRef> pathCF(AdoptCF, CFURLCopyFileSystemPath(url.get(), kCFURLPOSIXPathStyle));
758    if (!pathCF)
759        return;
760
761    wstring path = cfStringRefToWString(pathCF.get());
762
763    wstring resultPath;
764    if (!resolveCygwinPath(path, resultPath))
765        return;
766
767    // The path has been resolved, now convert it back to a CFURL.
768    int result = WideCharToMultiByte(CP_UTF8, 0, resultPath.c_str(), resultPath.size() + 1, 0, 0, 0, 0);
769    Vector<char> utf8Vector(result);
770    result = WideCharToMultiByte(CP_UTF8, 0, resultPath.c_str(), resultPath.size() + 1, utf8Vector.data(), result, 0, 0);
771    if (!result)
772        return;
773
774    url = CFURLCreateFromFileSystemRepresentation(0, (const UInt8*)utf8Vector.data(), utf8Vector.size() - 1, false);
775    if (!url)
776        return;
777
778    resultPath = cfStringRefToWString(CFURLGetString(url.get()));
779
780    BSTR resultPathBSTR = SysAllocStringLen(resultPath.data(), resultPath.size());
781    preferences->setUserStyleSheetLocation(resultPathBSTR);
782    SysFreeString(resultPathBSTR);
783}
784
785void LayoutTestController::setValueForUser(JSContextRef context, JSValueRef element, JSStringRef value)
786{
787    // FIXME: implement
788}
789
790void LayoutTestController::setViewModeMediaFeature(JSStringRef mode)
791{
792    // FIXME: implement
793}
794
795void LayoutTestController::setPersistentUserStyleSheetLocation(JSStringRef jsURL)
796{
797    RetainPtr<CFStringRef> urlString(AdoptCF, JSStringCopyCFString(0, jsURL));
798    ::setPersistentUserStyleSheetLocation(urlString.get());
799}
800
801void LayoutTestController::clearPersistentUserStyleSheet()
802{
803    ::setPersistentUserStyleSheetLocation(0);
804}
805
806void LayoutTestController::setWindowIsKey(bool flag)
807{
808    COMPtr<IWebView> webView;
809    if (FAILED(frame->webView(&webView)))
810        return;
811
812    COMPtr<IWebViewPrivate> viewPrivate;
813    if (FAILED(webView->QueryInterface(&viewPrivate)))
814        return;
815
816    HWND webViewWindow;
817    if (FAILED(viewPrivate->viewWindow((OLE_HANDLE*)&webViewWindow)))
818        return;
819
820    ::SendMessage(webViewWindow, flag ? WM_SETFOCUS : WM_KILLFOCUS, (WPARAM)::GetDesktopWindow(), 0);
821}
822
823void LayoutTestController::setSmartInsertDeleteEnabled(bool flag)
824{
825    COMPtr<IWebView> webView;
826    if (FAILED(frame->webView(&webView)))
827        return;
828
829    COMPtr<IWebViewEditing> viewEditing;
830    if (FAILED(webView->QueryInterface(&viewEditing)))
831        return;
832
833    viewEditing->setSmartInsertDeleteEnabled(flag ? TRUE : FALSE);
834}
835
836void LayoutTestController::setJavaScriptProfilingEnabled(bool flag)
837{
838    COMPtr<IWebView> webView;
839    if (FAILED(frame->webView(&webView)))
840        return;
841
842    COMPtr<IWebViewPrivate> viewPrivate;
843    if (FAILED(webView->QueryInterface(&viewPrivate)))
844        return;
845
846    COMPtr<IWebInspector> inspector;
847    if (FAILED(viewPrivate->inspector(&inspector)))
848        return;
849
850    setDeveloperExtrasEnabled(flag);
851    inspector->setJavaScriptProfilingEnabled(flag);
852}
853
854void LayoutTestController::setSelectTrailingWhitespaceEnabled(bool flag)
855{
856    COMPtr<IWebView> webView;
857    if (FAILED(frame->webView(&webView)))
858        return;
859
860    COMPtr<IWebViewEditing> viewEditing;
861    if (FAILED(webView->QueryInterface(&viewEditing)))
862        return;
863
864    viewEditing->setSelectTrailingWhitespaceEnabled(flag ? TRUE : FALSE);
865}
866
867static const CFTimeInterval waitToDumpWatchdogInterval = 30.0;
868
869static void CALLBACK waitUntilDoneWatchdogFired(HWND, UINT, UINT_PTR, DWORD)
870{
871    gLayoutTestController->waitToDumpWatchdogTimerFired();
872}
873
874void LayoutTestController::setWaitToDump(bool waitUntilDone)
875{
876    m_waitToDump = waitUntilDone;
877    if (m_waitToDump && !waitToDumpWatchdog)
878        waitToDumpWatchdog = SetTimer(0, 0, waitToDumpWatchdogInterval * 1000, waitUntilDoneWatchdogFired);
879}
880
881int LayoutTestController::windowCount()
882{
883    return openWindows().size();
884}
885
886bool LayoutTestController::elementDoesAutoCompleteForElementWithId(JSStringRef id)
887{
888    COMPtr<IDOMDocument> document;
889    if (FAILED(frame->DOMDocument(&document)))
890        return false;
891
892    wstring idWstring = jsStringRefToWString(id);
893    BSTR idBSTR = SysAllocStringLen((OLECHAR*)idWstring.c_str(), idWstring.length());
894    COMPtr<IDOMElement> element;
895    HRESULT result = document->getElementById(idBSTR, &element);
896    SysFreeString(idBSTR);
897
898    if (FAILED(result))
899        return false;
900
901    COMPtr<IWebFramePrivate> framePrivate(Query, frame);
902    if (!framePrivate)
903        return false;
904
905    BOOL autoCompletes;
906    if (FAILED(framePrivate->elementDoesAutoComplete(element.get(), &autoCompletes)))
907        return false;
908
909    return autoCompletes;
910}
911
912void LayoutTestController::execCommand(JSStringRef name, JSStringRef value)
913{
914    wstring wName = jsStringRefToWString(name);
915    wstring wValue = jsStringRefToWString(value);
916
917    COMPtr<IWebView> webView;
918    if (FAILED(frame->webView(&webView)))
919        return;
920
921    COMPtr<IWebViewPrivate> viewPrivate;
922    if (FAILED(webView->QueryInterface(&viewPrivate)))
923        return;
924
925    BSTR nameBSTR = SysAllocStringLen((OLECHAR*)wName.c_str(), wName.length());
926    BSTR valueBSTR = SysAllocStringLen((OLECHAR*)wValue.c_str(), wValue.length());
927    viewPrivate->executeCoreCommandByName(nameBSTR, valueBSTR);
928
929    SysFreeString(nameBSTR);
930    SysFreeString(valueBSTR);
931}
932
933bool LayoutTestController::findString(JSContextRef /* context */, JSStringRef /* target */, JSObjectRef /* optionsArray */)
934{
935    // FIXME: Implement
936    return false;
937}
938
939void LayoutTestController::setCacheModel(int)
940{
941    // FIXME: Implement
942}
943
944bool LayoutTestController::isCommandEnabled(JSStringRef /*name*/)
945{
946    printf("ERROR: LayoutTestController::isCommandEnabled() not implemented\n");
947    return false;
948}
949
950void LayoutTestController::clearAllApplicationCaches()
951{
952    // FIXME: Implement to support application cache quotas.
953}
954
955void LayoutTestController::clearApplicationCacheForOrigin(JSStringRef origin)
956{
957    // FIXME: Implement to support deleting all application cache for an origin.
958}
959
960void LayoutTestController::setApplicationCacheOriginQuota(unsigned long long quota)
961{
962    // FIXME: Implement to support application cache quotas.
963}
964
965JSValueRef LayoutTestController::originsWithApplicationCache(JSContextRef context)
966{
967    // FIXME: Implement to get origins that have application caches.
968    return JSValueMakeUndefined(context);
969}
970
971void LayoutTestController::clearAllDatabases()
972{
973    COMPtr<IWebDatabaseManager> databaseManager;
974    COMPtr<IWebDatabaseManager> tmpDatabaseManager;
975    if (FAILED(WebKitCreateInstance(CLSID_WebDatabaseManager, 0, IID_IWebDatabaseManager, (void**)&tmpDatabaseManager)))
976        return;
977    if (FAILED(tmpDatabaseManager->sharedWebDatabaseManager(&databaseManager)))
978        return;
979
980    databaseManager->deleteAllDatabases();
981}
982
983void LayoutTestController::overridePreference(JSStringRef key, JSStringRef value)
984{
985    COMPtr<IWebView> webView;
986    if (FAILED(frame->webView(&webView)))
987        return;
988
989    COMPtr<IWebPreferences> preferences;
990    if (FAILED(webView->preferences(&preferences)))
991        return;
992
993    COMPtr<IWebPreferencesPrivate> prefsPrivate(Query, preferences);
994    if (!prefsPrivate)
995        return;
996
997    BSTR keyBSTR = JSStringCopyBSTR(key);
998    BSTR valueBSTR = JSStringCopyBSTR(value);
999    prefsPrivate->setPreferenceForTest(keyBSTR, valueBSTR);
1000    SysFreeString(keyBSTR);
1001    SysFreeString(valueBSTR);
1002}
1003
1004void LayoutTestController::setDatabaseQuota(unsigned long long quota)
1005{
1006    COMPtr<IWebDatabaseManager> databaseManager;
1007    COMPtr<IWebDatabaseManager> tmpDatabaseManager;
1008
1009    if (FAILED(WebKitCreateInstance(CLSID_WebDatabaseManager, 0, IID_IWebDatabaseManager, (void**)&tmpDatabaseManager)))
1010        return;
1011    if (FAILED(tmpDatabaseManager->sharedWebDatabaseManager(&databaseManager)))
1012        return;
1013
1014    databaseManager->setQuota(TEXT("file:///"), quota);
1015}
1016
1017void LayoutTestController::setDomainRelaxationForbiddenForURLScheme(bool forbidden, JSStringRef scheme)
1018{
1019    COMPtr<IWebViewPrivate> webView;
1020    if (FAILED(WebKitCreateInstance(__uuidof(WebView), 0, __uuidof(webView), reinterpret_cast<void**>(&webView))))
1021        return;
1022
1023    BSTR schemeBSTR = JSStringCopyBSTR(scheme);
1024    webView->setDomainRelaxationForbiddenForURLScheme(forbidden, schemeBSTR);
1025    SysFreeString(schemeBSTR);
1026}
1027
1028void LayoutTestController::setAppCacheMaximumSize(unsigned long long size)
1029{
1030    printf("ERROR: LayoutTestController::setAppCacheMaximumSize() not implemented\n");
1031}
1032
1033bool LayoutTestController::pauseAnimationAtTimeOnElementWithId(JSStringRef animationName, double time, JSStringRef elementId)
1034{
1035    COMPtr<IDOMDocument> document;
1036    if (FAILED(frame->DOMDocument(&document)))
1037        return false;
1038
1039    BSTR idBSTR = JSStringCopyBSTR(elementId);
1040    COMPtr<IDOMElement> element;
1041    HRESULT hr = document->getElementById(idBSTR, &element);
1042    SysFreeString(idBSTR);
1043    if (FAILED(hr))
1044        return false;
1045
1046    COMPtr<IWebFramePrivate> framePrivate(Query, frame);
1047    if (!framePrivate)
1048        return false;
1049
1050    BSTR nameBSTR = JSStringCopyBSTR(animationName);
1051    BOOL wasRunning = FALSE;
1052    hr = framePrivate->pauseAnimation(nameBSTR, element.get(), time, &wasRunning);
1053    SysFreeString(nameBSTR);
1054
1055    return SUCCEEDED(hr) && wasRunning;
1056}
1057
1058bool LayoutTestController::pauseTransitionAtTimeOnElementWithId(JSStringRef propertyName, double time, JSStringRef elementId)
1059{
1060    COMPtr<IDOMDocument> document;
1061    if (FAILED(frame->DOMDocument(&document)))
1062        return false;
1063
1064    BSTR idBSTR = JSStringCopyBSTR(elementId);
1065    COMPtr<IDOMElement> element;
1066    HRESULT hr = document->getElementById(idBSTR, &element);
1067    SysFreeString(idBSTR);
1068    if (FAILED(hr))
1069        return false;
1070
1071    COMPtr<IWebFramePrivate> framePrivate(Query, frame);
1072    if (!framePrivate)
1073        return false;
1074
1075    BSTR nameBSTR = JSStringCopyBSTR(propertyName);
1076    BOOL wasRunning = FALSE;
1077    hr = framePrivate->pauseTransition(nameBSTR, element.get(), time, &wasRunning);
1078    SysFreeString(nameBSTR);
1079
1080    return SUCCEEDED(hr) && wasRunning;
1081}
1082
1083bool LayoutTestController::sampleSVGAnimationForElementAtTime(JSStringRef animationId, double time, JSStringRef elementId)
1084{
1085    COMPtr<IDOMDocument> document;
1086    if (FAILED(frame->DOMDocument(&document)))
1087        return false;
1088
1089    BSTR idBSTR = JSStringCopyBSTR(animationId);
1090    COMPtr<IDOMElement> element;
1091    HRESULT hr = document->getElementById(idBSTR, &element);
1092    SysFreeString(idBSTR);
1093    if (FAILED(hr))
1094        return false;
1095
1096    COMPtr<IWebFramePrivate> framePrivate(Query, frame);
1097    if (!framePrivate)
1098        return false;
1099
1100    BSTR elementIdBSTR = JSStringCopyBSTR(elementId);
1101    BOOL wasRunning = FALSE;
1102    hr = framePrivate->pauseSVGAnimation(elementIdBSTR, element.get(), time, &wasRunning);
1103    SysFreeString(elementIdBSTR);
1104
1105    return SUCCEEDED(hr) && wasRunning;
1106}
1107
1108unsigned LayoutTestController::numberOfActiveAnimations() const
1109{
1110    COMPtr<IWebFramePrivate> framePrivate(Query, frame);
1111    if (!framePrivate)
1112        return 0;
1113
1114    UINT number = 0;
1115    if (FAILED(framePrivate->numberOfActiveAnimations(&number)))
1116        return 0;
1117
1118    return number;
1119}
1120
1121void LayoutTestController::suspendAnimations() const
1122{
1123    COMPtr<IWebFramePrivate> framePrivate(Query, frame);
1124    if (!framePrivate)
1125        return;
1126
1127    framePrivate->suspendAnimations();
1128}
1129
1130void LayoutTestController::resumeAnimations() const
1131{
1132    COMPtr<IWebFramePrivate> framePrivate(Query, frame);
1133    if (!framePrivate)
1134        return;
1135
1136    framePrivate->resumeAnimations();
1137}
1138
1139static _bstr_t bstrT(JSStringRef jsString)
1140{
1141    // The false parameter tells the _bstr_t constructor to adopt the BSTR we pass it.
1142    return _bstr_t(JSStringCopyBSTR(jsString), false);
1143}
1144
1145void LayoutTestController::addOriginAccessWhitelistEntry(JSStringRef sourceOrigin, JSStringRef destinationProtocol, JSStringRef destinationHost, bool allowDestinationSubdomains)
1146{
1147    COMPtr<IWebViewPrivate> webView;
1148    if (FAILED(WebKitCreateInstance(__uuidof(WebView), 0, __uuidof(webView), reinterpret_cast<void**>(&webView))))
1149        return;
1150
1151    webView->addOriginAccessWhitelistEntry(bstrT(sourceOrigin).GetBSTR(), bstrT(destinationProtocol).GetBSTR(), bstrT(destinationHost).GetBSTR(), allowDestinationSubdomains);
1152}
1153
1154void LayoutTestController::removeOriginAccessWhitelistEntry(JSStringRef sourceOrigin, JSStringRef destinationProtocol, JSStringRef destinationHost, bool allowDestinationSubdomains)
1155{
1156    COMPtr<IWebViewPrivate> webView;
1157    if (FAILED(WebKitCreateInstance(__uuidof(WebView), 0, __uuidof(webView), reinterpret_cast<void**>(&webView))))
1158        return;
1159
1160    webView->removeOriginAccessWhitelistEntry(bstrT(sourceOrigin).GetBSTR(), bstrT(destinationProtocol).GetBSTR(), bstrT(destinationHost).GetBSTR(), allowDestinationSubdomains);
1161}
1162
1163void LayoutTestController::setScrollbarPolicy(JSStringRef orientation, JSStringRef policy)
1164{
1165    // FIXME: implement
1166}
1167
1168void LayoutTestController::addUserScript(JSStringRef source, bool runAtStart, bool allFrames)
1169{
1170    COMPtr<IWebViewPrivate> webView;
1171    if (FAILED(WebKitCreateInstance(__uuidof(WebView), 0, __uuidof(webView), reinterpret_cast<void**>(&webView))))
1172        return;
1173
1174    COMPtr<IWebScriptWorld> world;
1175    if (FAILED(WebKitCreateInstance(__uuidof(WebScriptWorld), 0, __uuidof(world), reinterpret_cast<void**>(&world))))
1176        return;
1177
1178    webView->addUserScriptToGroup(_bstr_t(L"org.webkit.DumpRenderTree").GetBSTR(), world.get(), bstrT(source).GetBSTR(), 0, 0, 0, 0, 0, runAtStart ? WebInjectAtDocumentStart : WebInjectAtDocumentEnd);
1179}
1180
1181
1182void LayoutTestController::addUserStyleSheet(JSStringRef source, bool allFrames)
1183{
1184    COMPtr<IWebViewPrivate> webView;
1185    if (FAILED(WebKitCreateInstance(__uuidof(WebView), 0, __uuidof(webView), reinterpret_cast<void**>(&webView))))
1186        return;
1187
1188    COMPtr<IWebScriptWorld> world;
1189    if (FAILED(WebKitCreateInstance(__uuidof(WebScriptWorld), 0, __uuidof(world), reinterpret_cast<void**>(&world))))
1190        return;
1191
1192    webView->addUserStyleSheetToGroup(_bstr_t(L"org.webkit.DumpRenderTree").GetBSTR(), world.get(), bstrT(source).GetBSTR(), 0, 0, 0, 0, 0);
1193}
1194
1195void LayoutTestController::setDeveloperExtrasEnabled(bool enabled)
1196{
1197    COMPtr<IWebView> webView;
1198    if (FAILED(frame->webView(&webView)))
1199        return;
1200
1201    COMPtr<IWebPreferences> preferences;
1202    if (FAILED(webView->preferences(&preferences)))
1203        return;
1204
1205    COMPtr<IWebPreferencesPrivate> prefsPrivate(Query, preferences);
1206    if (!prefsPrivate)
1207        return;
1208
1209    prefsPrivate->setDeveloperExtrasEnabled(enabled);
1210}
1211
1212void LayoutTestController::setAsynchronousSpellCheckingEnabled(bool)
1213{
1214    // FIXME: Implement this.
1215}
1216
1217void LayoutTestController::showWebInspector()
1218{
1219    COMPtr<IWebView> webView;
1220    if (FAILED(frame->webView(&webView)))
1221        return;
1222
1223    COMPtr<IWebViewPrivate> viewPrivate(Query, webView);
1224    if (!viewPrivate)
1225        return;
1226
1227    COMPtr<IWebInspector> inspector;
1228    if (SUCCEEDED(viewPrivate->inspector(&inspector)))
1229        inspector->show();
1230}
1231
1232void LayoutTestController::closeWebInspector()
1233{
1234    COMPtr<IWebView> webView;
1235    if (FAILED(frame->webView(&webView)))
1236        return;
1237
1238    COMPtr<IWebViewPrivate> viewPrivate(Query, webView);
1239    if (!viewPrivate)
1240        return;
1241
1242    COMPtr<IWebInspector> inspector;
1243    if (FAILED(viewPrivate->inspector(&inspector)))
1244        return;
1245
1246    inspector->close();
1247}
1248
1249void LayoutTestController::evaluateInWebInspector(long callId, JSStringRef script)
1250{
1251    COMPtr<IWebView> webView;
1252    if (FAILED(frame->webView(&webView)))
1253        return;
1254
1255    COMPtr<IWebViewPrivate> viewPrivate(Query, webView);
1256    if (!viewPrivate)
1257        return;
1258
1259    COMPtr<IWebInspector> inspector;
1260    if (FAILED(viewPrivate->inspector(&inspector)))
1261        return;
1262
1263    COMPtr<IWebInspectorPrivate> inspectorPrivate(Query, inspector);
1264    if (!inspectorPrivate)
1265        return;
1266
1267    inspectorPrivate->evaluateInFrontend(callId, bstrT(script).GetBSTR());
1268}
1269
1270typedef HashMap<unsigned, COMPtr<IWebScriptWorld> > WorldMap;
1271static WorldMap& worldMap()
1272{
1273    static WorldMap& map = *new WorldMap;
1274    return map;
1275}
1276
1277unsigned worldIDForWorld(IWebScriptWorld* world)
1278{
1279    WorldMap::const_iterator end = worldMap().end();
1280    for (WorldMap::const_iterator it = worldMap().begin(); it != end; ++it) {
1281        if (it->second == world)
1282            return it->first;
1283    }
1284
1285    return 0;
1286}
1287
1288void LayoutTestController::evaluateScriptInIsolatedWorld(unsigned worldID, JSObjectRef globalObject, JSStringRef script)
1289{
1290    COMPtr<IWebFramePrivate> framePrivate(Query, frame);
1291    if (!framePrivate)
1292        return;
1293
1294    // A worldID of 0 always corresponds to a new world. Any other worldID corresponds to a world
1295    // that is created once and cached forever.
1296    COMPtr<IWebScriptWorld> world;
1297    if (!worldID) {
1298        if (FAILED(WebKitCreateInstance(__uuidof(WebScriptWorld), 0, __uuidof(world), reinterpret_cast<void**>(&world))))
1299            return;
1300    } else {
1301        COMPtr<IWebScriptWorld>& worldSlot = worldMap().add(worldID, 0).first->second;
1302        if (!worldSlot && FAILED(WebKitCreateInstance(__uuidof(WebScriptWorld), 0, __uuidof(worldSlot), reinterpret_cast<void**>(&worldSlot))))
1303            return;
1304        world = worldSlot;
1305    }
1306
1307    BSTR result;
1308    if (FAILED(framePrivate->stringByEvaluatingJavaScriptInScriptWorld(world.get(), globalObject, bstrT(script).GetBSTR(), &result)))
1309        return;
1310    SysFreeString(result);
1311}
1312
1313void LayoutTestController::removeAllVisitedLinks()
1314{
1315    COMPtr<IWebHistory> history;
1316    if (FAILED(WebKitCreateInstance(CLSID_WebHistory, 0, __uuidof(history), reinterpret_cast<void**>(&history))))
1317        return;
1318
1319    COMPtr<IWebHistory> sharedHistory;
1320    if (FAILED(history->optionalSharedHistory(&sharedHistory)) || !sharedHistory)
1321        return;
1322
1323    COMPtr<IWebHistoryPrivate> sharedHistoryPrivate;
1324    if (FAILED(sharedHistory->QueryInterface(&sharedHistoryPrivate)))
1325        return;
1326
1327    sharedHistoryPrivate->removeAllVisitedLinks();
1328}
1329
1330JSRetainPtr<JSStringRef> LayoutTestController::counterValueForElementById(JSStringRef id)
1331{
1332    COMPtr<IWebFramePrivate> framePrivate(Query, frame);
1333    if (!framePrivate)
1334        return 0;
1335
1336    wstring idWstring = jsStringRefToWString(id);
1337    BSTR idBSTR = SysAllocStringLen((OLECHAR*)idWstring.c_str(), idWstring.length());
1338    BSTR counterValueBSTR;
1339    if (FAILED(framePrivate->counterValueForElementById(idBSTR, &counterValueBSTR)))
1340        return 0;
1341
1342    wstring counterValue(counterValueBSTR, SysStringLen(counterValueBSTR));
1343    SysFreeString(idBSTR);
1344    SysFreeString(counterValueBSTR);
1345    JSRetainPtr<JSStringRef> counterValueJS(Adopt, JSStringCreateWithCharacters(counterValue.data(), counterValue.length()));
1346    return counterValueJS;
1347}
1348
1349int LayoutTestController::pageNumberForElementById(JSStringRef id, float pageWidthInPixels, float pageHeightInPixels)
1350{
1351    COMPtr<IWebFramePrivate> framePrivate(Query, frame);
1352    if (!framePrivate)
1353        return 0;
1354
1355    wstring idWstring = jsStringRefToWString(id);
1356    BSTR idBSTR = SysAllocStringLen((OLECHAR*)idWstring.c_str(), idWstring.length());
1357    int pageNumber = -1;
1358    if (FAILED(framePrivate->pageNumberForElementById(idBSTR, pageWidthInPixels, pageHeightInPixels, &pageNumber)))
1359        pageNumber = -1;
1360    SysFreeString(idBSTR);
1361    return pageNumber;
1362}
1363
1364int LayoutTestController::numberOfPages(float pageWidthInPixels, float pageHeightInPixels)
1365{
1366    COMPtr<IWebFramePrivate> framePrivate(Query, frame);
1367    if (!framePrivate)
1368        return 0;
1369
1370    int pageNumber = -1;
1371    if (FAILED(framePrivate->numberOfPages(pageWidthInPixels, pageHeightInPixels, &pageNumber)))
1372        pageNumber = -1;
1373    return pageNumber;
1374}
1375
1376JSRetainPtr<JSStringRef> LayoutTestController::pageProperty(const char* propertyName, int pageNumber) const
1377{
1378    // FIXME: Implement this.
1379    return JSRetainPtr<JSStringRef>();
1380}
1381
1382void LayoutTestController::apiTestNewWindowDataLoadBaseURL(JSStringRef utf8Data, JSStringRef baseURL)
1383{
1384
1385}
1386
1387bool LayoutTestController::isPageBoxVisible(int pageNumber) const
1388{
1389    // FIXME: implement
1390    return false;
1391}
1392
1393JSRetainPtr<JSStringRef> LayoutTestController::pageSizeAndMarginsInPixels(int pageNumber, int width, int height, int marginTop, int marginRight, int marginBottom, int marginLeft) const
1394{
1395    // FIXME: implement
1396    return JSRetainPtr<JSStringRef>();
1397}
1398
1399void LayoutTestController::apiTestGoToCurrentBackForwardItem()
1400{
1401    COMPtr<IWebView> webView;
1402    if (FAILED(frame->webView(&webView)))
1403        return;
1404
1405    COMPtr<IWebBackForwardList> backForwardList;
1406    if (FAILED(webView->backForwardList(&backForwardList)))
1407        return;
1408
1409    COMPtr<IWebHistoryItem> item;
1410    if (FAILED(backForwardList->currentItem(&item)))
1411        return;
1412
1413    BOOL success;
1414    webView->goToBackForwardItem(item.get(), &success);
1415}
1416
1417void LayoutTestController::setWebViewEditable(bool)
1418{
1419}
1420
1421void LayoutTestController::authenticateSession(JSStringRef, JSStringRef, JSStringRef)
1422{
1423}
1424
1425void LayoutTestController::setEditingBehavior(const char* editingBehavior)
1426{
1427    COMPtr<IWebView> webView;
1428    if (FAILED(frame->webView(&webView)))
1429        return;
1430
1431    COMPtr<IWebPreferences> preferences;
1432    if (FAILED(webView->preferences(&preferences)))
1433        return;
1434
1435    string behaviorString(editingBehavior);
1436    if (behaviorString == "mac")
1437        preferences->setEditingBehavior(WebKitEditingMacBehavior);
1438    else if (behaviorString == "win")
1439        preferences->setEditingBehavior(WebKitEditingWinBehavior);
1440    else if (behaviorString == "unix")
1441        preferences->setEditingBehavior(WebKitEditingUnixBehavior);
1442}
1443
1444JSValueRef LayoutTestController::shadowRoot(JSContextRef context, JSValueRef jsElement)
1445{
1446    // FIXME: Implement this.
1447    return JSValueMakeUndefined(context);
1448}
1449
1450void LayoutTestController::abortModal()
1451{
1452}
1453
1454bool LayoutTestController::hasSpellingMarker(int from, int length)
1455{
1456    COMPtr<IWebFramePrivate> framePrivate(Query, frame);
1457    if (!framePrivate)
1458        return false;
1459    BOOL ret = FALSE;
1460    if (FAILED(framePrivate->hasSpellingMarker(from, length, &ret)))
1461        return false;
1462    return ret;
1463}
1464
1465bool LayoutTestController::hasGrammarMarker(int from, int length)
1466{
1467    // FIXME: Implement this.
1468    return false;
1469}
1470
1471void LayoutTestController::dumpConfigurationForViewport(int /*deviceDPI*/, int /*deviceWidth*/, int /*deviceHeight*/, int /*availableWidth*/, int /*availableHeight*/)
1472{
1473    // FIXME: Implement this.
1474}
1475
1476void LayoutTestController::setSerializeHTTPLoads(bool)
1477{
1478    // FIXME: Implement.
1479}
1480
1481void LayoutTestController::syncLocalStorage()
1482{
1483    // FIXME: Implement.
1484}
1485
1486void LayoutTestController::observeStorageTrackerNotifications(unsigned number)
1487{
1488    // FIXME: Implement.
1489}
1490
1491void LayoutTestController::deleteAllLocalStorage()
1492{
1493    // FIXME: Implement.
1494}
1495
1496JSValueRef LayoutTestController::originsWithLocalStorage(JSContextRef context)
1497{
1498    // FIXME: Implement.
1499    return JSValueMakeUndefined(context);
1500}
1501
1502void LayoutTestController::deleteLocalStorageForOrigin(JSStringRef URL)
1503{
1504    // FIXME: Implement.
1505}
1506
1507void LayoutTestController::setMinimumTimerInterval(double minimumTimerInterval)
1508{
1509    COMPtr<IWebView> webView;
1510    if (FAILED(frame->webView(&webView)))
1511        return;
1512
1513    COMPtr<IWebViewPrivate> viewPrivate(Query, webView);
1514    if (!viewPrivate)
1515        return;
1516
1517    viewPrivate->setMinimumTimerInterval(minimumTimerInterval);
1518}
1519
1520
1521