Home | History | Annotate | Download | only in win
      1 /*
      2  * Copyright (C) 2006, 2007, 2008, 2009 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 
     54 using std::string;
     55 using std::wstring;
     56 
     57 static bool resolveCygwinPath(const wstring& cygwinPath, wstring& windowsPath);
     58 
     59 LayoutTestController::~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 
     82 void LayoutTestController::addDisallowedURL(JSStringRef url)
     83 {
     84     // FIXME: Implement!
     85 }
     86 
     87 void 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 
    113 JSStringRef LayoutTestController::copyDecodedHostName(JSStringRef name)
    114 {
    115     // FIXME: Implement!
    116     return 0;
    117 }
    118 
    119 JSStringRef LayoutTestController::copyEncodedHostName(JSStringRef name)
    120 {
    121     // FIXME: Implement!
    122     return 0;
    123 }
    124 
    125 void LayoutTestController::disableImageLoading()
    126 {
    127     COMPtr<IWebView> webView;
    128     if (FAILED(frame->webView(&webView)))
    129         return;
    130 
    131     COMPtr<IWebPreferences> preferences;
    132     if (FAILED(webView->preferences(&preferences)))
    133         return;
    134 
    135     preferences->setLoadsImagesAutomatically(FALSE);
    136 }
    137 
    138 void LayoutTestController::dispatchPendingLoadRequests()
    139 {
    140     // FIXME: Implement for testing fix for 6727495
    141 }
    142 
    143 void LayoutTestController::display()
    144 {
    145     displayWebView();
    146 }
    147 
    148 void LayoutTestController::keepWebHistory()
    149 {
    150     COMPtr<IWebHistory> history;
    151     if (FAILED(WebKitCreateInstance(CLSID_WebHistory, 0, __uuidof(history), reinterpret_cast<void**>(&history))))
    152         return;
    153 
    154     COMPtr<IWebHistory> sharedHistory;
    155     if (FAILED(WebKitCreateInstance(CLSID_WebHistory, 0, __uuidof(sharedHistory), reinterpret_cast<void**>(&sharedHistory))))
    156         return;
    157 
    158     history->setOptionalSharedHistory(sharedHistory.get());
    159 }
    160 
    161 void LayoutTestController::waitForPolicyDelegate()
    162 {
    163     // FIXME: Implement this.
    164 }
    165 
    166 size_t LayoutTestController::webHistoryItemCount()
    167 {
    168     COMPtr<IWebHistory> history;
    169     if (FAILED(WebKitCreateInstance(CLSID_WebHistory, 0, __uuidof(history), reinterpret_cast<void**>(&history))))
    170         return 0;
    171 
    172     COMPtr<IWebHistory> sharedHistory;
    173     if (FAILED(history->optionalSharedHistory(&sharedHistory)) || !sharedHistory)
    174         return 0;
    175 
    176     COMPtr<IWebHistoryPrivate> sharedHistoryPrivate;
    177     if (FAILED(sharedHistory->QueryInterface(&sharedHistoryPrivate)))
    178         return 0;
    179 
    180     int count;
    181     if (FAILED(sharedHistoryPrivate->allItems(&count, 0)))
    182         return 0;
    183 
    184     return count;
    185 }
    186 
    187 unsigned LayoutTestController::workerThreadCount() const
    188 {
    189     COMPtr<IWebWorkersPrivate> workers;
    190     if (FAILED(WebKitCreateInstance(CLSID_WebWorkersPrivate, 0, __uuidof(workers), reinterpret_cast<void**>(&workers))))
    191         return 0;
    192     unsigned count;
    193     if (FAILED(workers->workerThreadCount(&count)))
    194         return 0;
    195     return count;
    196 }
    197 
    198 void LayoutTestController::notifyDone()
    199 {
    200     // Same as on mac.  This can be shared.
    201     if (m_waitToDump && !topLoadingFrame && !WorkQueue::shared()->count())
    202         dump();
    203     m_waitToDump = false;
    204 }
    205 
    206 JSStringRef LayoutTestController::pathToLocalResource(JSContextRef context, JSStringRef url)
    207 {
    208     wstring input(JSStringGetCharactersPtr(url), JSStringGetLength(url));
    209 
    210     wstring localPath;
    211     if (!resolveCygwinPath(input, localPath)) {
    212         printf("ERROR: Failed to resolve Cygwin path %S\n", input.c_str());
    213         return 0;
    214     }
    215 
    216     return JSStringCreateWithCharacters(localPath.c_str(), localPath.length());
    217 }
    218 
    219 static wstring jsStringRefToWString(JSStringRef jsStr)
    220 {
    221     size_t length = JSStringGetLength(jsStr);
    222     Vector<WCHAR> buffer(length + 1);
    223     memcpy(buffer.data(), JSStringGetCharactersPtr(jsStr), length * sizeof(WCHAR));
    224     buffer[length] = '\0';
    225 
    226     return buffer.data();
    227 }
    228 
    229 void LayoutTestController::queueLoad(JSStringRef url, JSStringRef target)
    230 {
    231     COMPtr<IWebDataSource> dataSource;
    232     if (FAILED(frame->dataSource(&dataSource)))
    233         return;
    234 
    235     COMPtr<IWebURLResponse> response;
    236     if (FAILED(dataSource->response(&response)) || !response)
    237         return;
    238 
    239     BSTR responseURLBSTR;
    240     if (FAILED(response->URL(&responseURLBSTR)))
    241         return;
    242     wstring responseURL(responseURLBSTR, SysStringLen(responseURLBSTR));
    243     SysFreeString(responseURLBSTR);
    244 
    245     // FIXME: We should do real relative URL resolution here.
    246     int lastSlash = responseURL.rfind('/');
    247     if (lastSlash != -1)
    248         responseURL = responseURL.substr(0, lastSlash);
    249 
    250     wstring wURL = jsStringRefToWString(url);
    251     wstring wAbsoluteURL = responseURL + TEXT("/") + wURL;
    252     JSRetainPtr<JSStringRef> jsAbsoluteURL(Adopt, JSStringCreateWithCharacters(wAbsoluteURL.data(), wAbsoluteURL.length()));
    253 
    254     WorkQueue::shared()->queue(new LoadItem(jsAbsoluteURL.get(), target));
    255 }
    256 
    257 void LayoutTestController::setAcceptsEditing(bool acceptsEditing)
    258 {
    259     COMPtr<IWebView> webView;
    260     if (FAILED(frame->webView(&webView)))
    261         return;
    262 
    263     COMPtr<IWebViewEditing> viewEditing;
    264     if (FAILED(webView->QueryInterface(&viewEditing)))
    265         return;
    266 
    267     COMPtr<IWebEditingDelegate> delegate;
    268     if (FAILED(viewEditing->editingDelegate(&delegate)))
    269         return;
    270 
    271     EditingDelegate* editingDelegate = (EditingDelegate*)(IWebEditingDelegate*)delegate.get();
    272     editingDelegate->setAcceptsEditing(acceptsEditing);
    273 }
    274 
    275 void LayoutTestController::setAlwaysAcceptCookies(bool alwaysAcceptCookies)
    276 {
    277     if (alwaysAcceptCookies == m_alwaysAcceptCookies)
    278         return;
    279 
    280     if (!::setAlwaysAcceptCookies(alwaysAcceptCookies))
    281         return;
    282     m_alwaysAcceptCookies = alwaysAcceptCookies;
    283 }
    284 
    285 void LayoutTestController::setAuthorAndUserStylesEnabled(bool flag)
    286 {
    287     COMPtr<IWebView> webView;
    288     if (FAILED(frame->webView(&webView)))
    289         return;
    290 
    291     COMPtr<IWebPreferences> preferences;
    292     if (FAILED(webView->preferences(&preferences)))
    293         return;
    294 
    295     COMPtr<IWebPreferencesPrivate> prefsPrivate(Query, preferences);
    296     if (!prefsPrivate)
    297         return;
    298 
    299     prefsPrivate->setAuthorAndUserStylesEnabled(flag);
    300 }
    301 
    302 void LayoutTestController::setCustomPolicyDelegate(bool setDelegate, bool permissive)
    303 {
    304     COMPtr<IWebView> webView;
    305     if (FAILED(frame->webView(&webView)))
    306         return;
    307 
    308     if (setDelegate) {
    309         policyDelegate->setPermissive(permissive);
    310         webView->setPolicyDelegate(policyDelegate);
    311     } else
    312         webView->setPolicyDelegate(0);
    313 }
    314 
    315 void LayoutTestController::setMockGeolocationPosition(double latitude, double longitude, double accuracy)
    316 {
    317     // FIXME: Implement for Geolocation layout tests.
    318     // See https://bugs.webkit.org/show_bug.cgi?id=28264.
    319 }
    320 
    321 void LayoutTestController::setMockGeolocationError(int code, JSStringRef message)
    322 {
    323     // FIXME: Implement for Geolocation layout tests.
    324     // See https://bugs.webkit.org/show_bug.cgi?id=28264.
    325 }
    326 
    327 void LayoutTestController::setIconDatabaseEnabled(bool iconDatabaseEnabled)
    328 {
    329     // See also <rdar://problem/6480108>
    330     COMPtr<IWebIconDatabase> iconDatabase;
    331     COMPtr<IWebIconDatabase> tmpIconDatabase;
    332     if (FAILED(WebKitCreateInstance(CLSID_WebIconDatabase, 0, IID_IWebIconDatabase, (void**)&tmpIconDatabase)))
    333         return;
    334     if (FAILED(tmpIconDatabase->sharedIconDatabase(&iconDatabase)))
    335         return;
    336 
    337     iconDatabase->setEnabled(iconDatabaseEnabled);
    338 }
    339 
    340 void LayoutTestController::setMainFrameIsFirstResponder(bool flag)
    341 {
    342     // FIXME: Implement!
    343 }
    344 
    345 void LayoutTestController::setPrivateBrowsingEnabled(bool privateBrowsingEnabled)
    346 {
    347     COMPtr<IWebView> webView;
    348     if (FAILED(frame->webView(&webView)))
    349         return;
    350 
    351     COMPtr<IWebPreferences> preferences;
    352     if (FAILED(webView->preferences(&preferences)))
    353         return;
    354 
    355     preferences->setPrivateBrowsingEnabled(privateBrowsingEnabled);
    356 }
    357 
    358 void LayoutTestController::setXSSAuditorEnabled(bool enabled)
    359 {
    360     COMPtr<IWebView> webView;
    361     if (FAILED(frame->webView(&webView)))
    362         return;
    363 
    364     COMPtr<IWebPreferences> preferences;
    365     if (FAILED(webView->preferences(&preferences)))
    366         return;
    367 
    368     COMPtr<IWebPreferencesPrivate> prefsPrivate(Query, preferences);
    369     if (!prefsPrivate)
    370         return;
    371 
    372     prefsPrivate->setXSSAuditorEnabled(enabled);
    373 }
    374 
    375 void LayoutTestController::setFrameSetFlatteningEnabled(bool enabled)
    376 {
    377     COMPtr<IWebView> webView;
    378     if (FAILED(frame->webView(&webView)))
    379         return;
    380 
    381     COMPtr<IWebPreferences> preferences;
    382     if (FAILED(webView->preferences(&preferences)))
    383         return;
    384 
    385     COMPtr<IWebPreferencesPrivate> prefsPrivate(Query, preferences);
    386     if (!prefsPrivate)
    387         return;
    388 
    389     prefsPrivate->setFrameSetFlatteningEnabled(enabled);
    390 }
    391 
    392 void LayoutTestController::setAllowUniversalAccessFromFileURLs(bool enabled)
    393 {
    394     COMPtr<IWebView> webView;
    395     if (FAILED(frame->webView(&webView)))
    396         return;
    397 
    398     COMPtr<IWebPreferences> preferences;
    399     if (FAILED(webView->preferences(&preferences)))
    400         return;
    401 
    402     COMPtr<IWebPreferencesPrivate> prefsPrivate(Query, preferences);
    403     if (!prefsPrivate)
    404         return;
    405 
    406     prefsPrivate->setAllowUniversalAccessFromFileURLs(enabled);
    407 }
    408 
    409 void LayoutTestController::setPopupBlockingEnabled(bool enabled)
    410 {
    411     COMPtr<IWebView> webView;
    412     if (FAILED(frame->webView(&webView)))
    413         return;
    414 
    415     COMPtr<IWebPreferences> preferences;
    416     if (FAILED(webView->preferences(&preferences)))
    417         return;
    418 
    419     preferences->setJavaScriptCanOpenWindowsAutomatically(!enabled);
    420 }
    421 
    422 void LayoutTestController::setTabKeyCyclesThroughElements(bool shouldCycle)
    423 {
    424     COMPtr<IWebView> webView;
    425     if (FAILED(frame->webView(&webView)))
    426         return;
    427 
    428     COMPtr<IWebViewPrivate> viewPrivate;
    429     if (FAILED(webView->QueryInterface(&viewPrivate)))
    430         return;
    431 
    432     viewPrivate->setTabKeyCyclesThroughElements(shouldCycle ? TRUE : FALSE);
    433 }
    434 
    435 void LayoutTestController::setTimelineProfilingEnabled(bool flag)
    436 {
    437     COMPtr<IWebView> webView;
    438     if (FAILED(frame->webView(&webView)))
    439         return;
    440 
    441     COMPtr<IWebViewPrivate> viewPrivate;
    442     if (FAILED(webView->QueryInterface(&viewPrivate)))
    443         return;
    444 
    445     COMPtr<IWebInspector> inspector;
    446     if (FAILED(viewPrivate->inspector(&inspector)))
    447         return;
    448 
    449     inspector->setTimelineProfilingEnabled(flag);
    450 }
    451 
    452 void LayoutTestController::setUseDashboardCompatibilityMode(bool flag)
    453 {
    454     // FIXME: Implement!
    455 }
    456 
    457 void LayoutTestController::setUserStyleSheetEnabled(bool flag)
    458 {
    459     COMPtr<IWebView> webView;
    460     if (FAILED(frame->webView(&webView)))
    461         return;
    462 
    463     COMPtr<IWebPreferences> preferences;
    464     if (FAILED(webView->preferences(&preferences)))
    465         return;
    466 
    467    preferences->setUserStyleSheetEnabled(flag);
    468 }
    469 
    470 bool appendComponentToPath(wstring& path, const wstring& component)
    471 {
    472     WCHAR buffer[MAX_PATH];
    473 
    474     if (path.size() + 1 > MAX_PATH)
    475         return false;
    476 
    477     memcpy(buffer, path.data(), path.size() * sizeof(WCHAR));
    478     buffer[path.size()] = '\0';
    479 
    480     if (!PathAppendW(buffer, component.c_str()))
    481         return false;
    482 
    483     path = wstring(buffer);
    484     return true;
    485 }
    486 
    487 static bool followShortcuts(wstring& path)
    488 {
    489     if (PathFileExists(path.c_str()))
    490         return true;
    491 
    492     // Do we have a shortcut?
    493     wstring linkPath = path;
    494     linkPath.append(TEXT(".lnk"));
    495     if (!PathFileExists(linkPath.c_str()))
    496        return true;
    497 
    498     // We have a shortcut, find its target.
    499     COMPtr<IShellLink> shortcut(Create, CLSID_ShellLink);
    500     if (!shortcut)
    501        return false;
    502     COMPtr<IPersistFile> persistFile(Query, shortcut);
    503     if (!shortcut)
    504         return false;
    505     if (FAILED(persistFile->Load(linkPath.c_str(), STGM_READ)))
    506         return false;
    507     if (FAILED(shortcut->Resolve(0, 0)))
    508         return false;
    509     WCHAR targetPath[MAX_PATH];
    510     DWORD targetPathLen = _countof(targetPath);
    511     if (FAILED(shortcut->GetPath(targetPath, targetPathLen, 0, 0)))
    512         return false;
    513     if (!PathFileExists(targetPath))
    514         return false;
    515     // Use the target path as the result path instead.
    516     path = wstring(targetPath);
    517 
    518     return true;
    519 }
    520 
    521 static bool resolveCygwinPath(const wstring& cygwinPath, wstring& windowsPath)
    522 {
    523     wstring fileProtocol = L"file://";
    524     bool isFileProtocol = cygwinPath.find(fileProtocol) != string::npos;
    525     if (cygwinPath[isFileProtocol ? 7 : 0] != '/')  // ensure path is absolute
    526         return false;
    527 
    528     // Get the Root path.
    529     WCHAR rootPath[MAX_PATH];
    530     DWORD rootPathSize = _countof(rootPath);
    531     DWORD keyType;
    532     DWORD result = ::SHGetValueW(HKEY_LOCAL_MACHINE, TEXT("SOFTWARE\\Cygnus Solutions\\Cygwin\\mounts v2\\/"), TEXT("native"), &keyType, &rootPath, &rootPathSize);
    533 
    534     if (result != ERROR_SUCCESS || keyType != REG_SZ)
    535         return false;
    536 
    537     windowsPath = wstring(rootPath, rootPathSize);
    538 
    539     int oldPos = isFileProtocol ? 8 : 1;
    540     while (1) {
    541         int newPos = cygwinPath.find('/', oldPos);
    542 
    543         if (newPos == -1) {
    544             wstring pathComponent = cygwinPath.substr(oldPos);
    545 
    546             if (!appendComponentToPath(windowsPath, pathComponent))
    547                return false;
    548 
    549             if (!followShortcuts(windowsPath))
    550                 return false;
    551 
    552             break;
    553         }
    554 
    555         wstring pathComponent = cygwinPath.substr(oldPos, newPos - oldPos);
    556         if (!appendComponentToPath(windowsPath, pathComponent))
    557             return false;
    558 
    559         if (!followShortcuts(windowsPath))
    560             return false;
    561 
    562         oldPos = newPos + 1;
    563     }
    564 
    565     if (isFileProtocol)
    566         windowsPath = fileProtocol + windowsPath;
    567 
    568     return true;
    569 }
    570 
    571 static wstring cfStringRefToWString(CFStringRef cfStr)
    572 {
    573     Vector<wchar_t> v(CFStringGetLength(cfStr));
    574     CFStringGetCharacters(cfStr, CFRangeMake(0, CFStringGetLength(cfStr)), (UniChar *)v.data());
    575 
    576     return wstring(v.data(), v.size());
    577 }
    578 
    579 void LayoutTestController::setUserStyleSheetLocation(JSStringRef jsURL)
    580 {
    581     COMPtr<IWebView> webView;
    582     if (FAILED(frame->webView(&webView)))
    583         return;
    584 
    585     COMPtr<IWebPreferences> preferences;
    586     if (FAILED(webView->preferences(&preferences)))
    587         return;
    588 
    589     RetainPtr<CFStringRef> urlString(AdoptCF, JSStringCopyCFString(0, jsURL));
    590     RetainPtr<CFURLRef> url(AdoptCF, CFURLCreateWithString(0, urlString.get(), 0));
    591     if (!url)
    592         return;
    593 
    594     // Now copy the file system path, POSIX style.
    595     RetainPtr<CFStringRef> pathCF(AdoptCF, CFURLCopyFileSystemPath(url.get(), kCFURLPOSIXPathStyle));
    596     if (!pathCF)
    597         return;
    598 
    599     wstring path = cfStringRefToWString(pathCF.get());
    600 
    601     wstring resultPath;
    602     if (!resolveCygwinPath(path, resultPath))
    603         return;
    604 
    605     // The path has been resolved, now convert it back to a CFURL.
    606     int result = WideCharToMultiByte(CP_UTF8, 0, resultPath.c_str(), resultPath.size() + 1, 0, 0, 0, 0);
    607     Vector<char> utf8Vector(result);
    608     result = WideCharToMultiByte(CP_UTF8, 0, resultPath.c_str(), resultPath.size() + 1, utf8Vector.data(), result, 0, 0);
    609     if (!result)
    610         return;
    611 
    612     url = CFURLCreateFromFileSystemRepresentation(0, (const UInt8*)utf8Vector.data(), utf8Vector.size() - 1, false);
    613     if (!url)
    614         return;
    615 
    616     resultPath = cfStringRefToWString(CFURLGetString(url.get()));
    617 
    618     BSTR resultPathBSTR = SysAllocStringLen(resultPath.data(), resultPath.size());
    619     preferences->setUserStyleSheetLocation(resultPathBSTR);
    620     SysFreeString(resultPathBSTR);
    621 }
    622 
    623 void LayoutTestController::setPersistentUserStyleSheetLocation(JSStringRef jsURL)
    624 {
    625     RetainPtr<CFStringRef> urlString(AdoptCF, JSStringCopyCFString(0, jsURL));
    626     ::setPersistentUserStyleSheetLocation(urlString.get());
    627 }
    628 
    629 void LayoutTestController::clearPersistentUserStyleSheet()
    630 {
    631     ::setPersistentUserStyleSheetLocation(0);
    632 }
    633 
    634 void LayoutTestController::setWindowIsKey(bool flag)
    635 {
    636     COMPtr<IWebView> webView;
    637     if (FAILED(frame->webView(&webView)))
    638         return;
    639 
    640     COMPtr<IWebViewPrivate> viewPrivate;
    641     if (FAILED(webView->QueryInterface(&viewPrivate)))
    642         return;
    643 
    644     HWND webViewWindow;
    645     if (FAILED(viewPrivate->viewWindow((OLE_HANDLE*)&webViewWindow)))
    646         return;
    647 
    648     ::SendMessage(webViewWindow, flag ? WM_SETFOCUS : WM_KILLFOCUS, (WPARAM)::GetDesktopWindow(), 0);
    649 }
    650 
    651 void LayoutTestController::setSmartInsertDeleteEnabled(bool flag)
    652 {
    653     COMPtr<IWebView> webView;
    654     if (FAILED(frame->webView(&webView)))
    655         return;
    656 
    657     COMPtr<IWebViewEditing> viewEditing;
    658     if (FAILED(webView->QueryInterface(&viewEditing)))
    659         return;
    660 
    661     viewEditing->setSmartInsertDeleteEnabled(flag ? TRUE : FALSE);
    662 }
    663 
    664 void LayoutTestController::setJavaScriptProfilingEnabled(bool flag)
    665 {
    666     COMPtr<IWebView> webView;
    667     if (FAILED(frame->webView(&webView)))
    668         return;
    669 
    670     COMPtr<IWebViewPrivate> viewPrivate;
    671     if (FAILED(webView->QueryInterface(&viewPrivate)))
    672         return;
    673 
    674     COMPtr<IWebPreferences> preferences;
    675     if (FAILED(webView->preferences(&preferences)))
    676         return;
    677 
    678     COMPtr<IWebPreferencesPrivate> prefsPrivate(Query, preferences);
    679     if (!prefsPrivate)
    680         return;
    681 
    682     COMPtr<IWebInspector> inspector;
    683     if (FAILED(viewPrivate->inspector(&inspector)))
    684         return;
    685 
    686     prefsPrivate->setDeveloperExtrasEnabled(flag);
    687     inspector->setJavaScriptProfilingEnabled(flag);
    688 }
    689 
    690 void LayoutTestController::setSelectTrailingWhitespaceEnabled(bool flag)
    691 {
    692     COMPtr<IWebView> webView;
    693     if (FAILED(frame->webView(&webView)))
    694         return;
    695 
    696     COMPtr<IWebViewEditing> viewEditing;
    697     if (FAILED(webView->QueryInterface(&viewEditing)))
    698         return;
    699 
    700     viewEditing->setSelectTrailingWhitespaceEnabled(flag ? TRUE : FALSE);
    701 }
    702 
    703 static const CFTimeInterval waitToDumpWatchdogInterval = 15.0;
    704 
    705 static void CALLBACK waitUntilDoneWatchdogFired(HWND, UINT, UINT_PTR, DWORD)
    706 {
    707     gLayoutTestController->waitToDumpWatchdogTimerFired();
    708 }
    709 
    710 void LayoutTestController::setWaitToDump(bool waitUntilDone)
    711 {
    712     m_waitToDump = waitUntilDone;
    713     if (m_waitToDump && !waitToDumpWatchdog)
    714         waitToDumpWatchdog = SetTimer(0, 0, waitToDumpWatchdogInterval * 1000, waitUntilDoneWatchdogFired);
    715 }
    716 
    717 int LayoutTestController::windowCount()
    718 {
    719     return openWindows().size();
    720 }
    721 
    722 bool LayoutTestController::elementDoesAutoCompleteForElementWithId(JSStringRef id)
    723 {
    724     COMPtr<IDOMDocument> document;
    725     if (FAILED(frame->DOMDocument(&document)))
    726         return false;
    727 
    728     wstring idWstring = jsStringRefToWString(id);
    729     BSTR idBSTR = SysAllocStringLen((OLECHAR*)idWstring.c_str(), idWstring.length());
    730     COMPtr<IDOMElement> element;
    731     HRESULT result = document->getElementById(idBSTR, &element);
    732     SysFreeString(idBSTR);
    733 
    734     if (FAILED(result))
    735         return false;
    736 
    737     COMPtr<IWebFramePrivate> framePrivate(Query, frame);
    738     if (!framePrivate)
    739         return false;
    740 
    741     BOOL autoCompletes;
    742     if (FAILED(framePrivate->elementDoesAutoComplete(element.get(), &autoCompletes)))
    743         return false;
    744 
    745     return autoCompletes;
    746 }
    747 
    748 void LayoutTestController::execCommand(JSStringRef name, JSStringRef value)
    749 {
    750     wstring wName = jsStringRefToWString(name);
    751     wstring wValue = jsStringRefToWString(value);
    752 
    753     COMPtr<IWebView> webView;
    754     if (FAILED(frame->webView(&webView)))
    755         return;
    756 
    757     COMPtr<IWebViewPrivate> viewPrivate;
    758     if (FAILED(webView->QueryInterface(&viewPrivate)))
    759         return;
    760 
    761     BSTR nameBSTR = SysAllocStringLen((OLECHAR*)wName.c_str(), wName.length());
    762     BSTR valueBSTR = SysAllocStringLen((OLECHAR*)wValue.c_str(), wValue.length());
    763     viewPrivate->executeCoreCommandByName(nameBSTR, valueBSTR);
    764 
    765     SysFreeString(nameBSTR);
    766     SysFreeString(valueBSTR);
    767 }
    768 
    769 void LayoutTestController::setCacheModel(int)
    770 {
    771     // FIXME: Implement
    772 }
    773 
    774 bool LayoutTestController::isCommandEnabled(JSStringRef /*name*/)
    775 {
    776     printf("ERROR: LayoutTestController::isCommandEnabled() not implemented\n");
    777     return false;
    778 }
    779 
    780 void LayoutTestController::clearAllDatabases()
    781 {
    782     COMPtr<IWebDatabaseManager> databaseManager;
    783     COMPtr<IWebDatabaseManager> tmpDatabaseManager;
    784     if (FAILED(WebKitCreateInstance(CLSID_WebDatabaseManager, 0, IID_IWebDatabaseManager, (void**)&tmpDatabaseManager)))
    785         return;
    786     if (FAILED(tmpDatabaseManager->sharedWebDatabaseManager(&databaseManager)))
    787         return;
    788 
    789     databaseManager->deleteAllDatabases();
    790 }
    791 
    792 void LayoutTestController::overridePreference(JSStringRef key, JSStringRef value)
    793 {
    794     COMPtr<IWebView> webView;
    795     if (FAILED(frame->webView(&webView)))
    796         return;
    797 
    798     COMPtr<IWebPreferences> preferences;
    799     if (FAILED(webView->preferences(&preferences)))
    800         return;
    801 
    802     COMPtr<IWebPreferencesPrivate> prefsPrivate(Query, preferences);
    803     if (!prefsPrivate)
    804         return;
    805 
    806     BSTR keyBSTR = JSStringCopyBSTR(key);
    807     BSTR valueBSTR = JSStringCopyBSTR(value);
    808     prefsPrivate->setPreferenceForTest(keyBSTR, valueBSTR);
    809     SysFreeString(keyBSTR);
    810     SysFreeString(valueBSTR);
    811 }
    812 
    813 void LayoutTestController::setDatabaseQuota(unsigned long long quota)
    814 {
    815     COMPtr<IWebDatabaseManager> databaseManager;
    816     COMPtr<IWebDatabaseManager> tmpDatabaseManager;
    817 
    818     if (FAILED(WebKitCreateInstance(CLSID_WebDatabaseManager, 0, IID_IWebDatabaseManager, (void**)&tmpDatabaseManager)))
    819         return;
    820     if (FAILED(tmpDatabaseManager->sharedWebDatabaseManager(&databaseManager)))
    821         return;
    822 
    823     databaseManager->setQuota(TEXT("file:///"), quota);
    824 }
    825 
    826 void LayoutTestController::setDomainRelaxationForbiddenForURLScheme(bool forbidden, JSStringRef scheme)
    827 {
    828     COMPtr<IWebViewPrivate> webView;
    829     if (FAILED(WebKitCreateInstance(__uuidof(WebView), 0, __uuidof(webView), reinterpret_cast<void**>(&webView))))
    830         return;
    831 
    832     BSTR schemeBSTR = JSStringCopyBSTR(scheme);
    833     webView->setDomainRelaxationForbiddenForURLScheme(forbidden, schemeBSTR);
    834     SysFreeString(schemeBSTR);
    835 }
    836 
    837 void LayoutTestController::setAppCacheMaximumSize(unsigned long long size)
    838 {
    839     printf("ERROR: LayoutTestController::setAppCacheMaximumSize() not implemented\n");
    840 }
    841 
    842 bool LayoutTestController::pauseAnimationAtTimeOnElementWithId(JSStringRef animationName, double time, JSStringRef elementId)
    843 {
    844     COMPtr<IDOMDocument> document;
    845     if (FAILED(frame->DOMDocument(&document)))
    846         return false;
    847 
    848     BSTR idBSTR = JSStringCopyBSTR(elementId);
    849     COMPtr<IDOMElement> element;
    850     HRESULT hr = document->getElementById(idBSTR, &element);
    851     SysFreeString(idBSTR);
    852     if (FAILED(hr))
    853         return false;
    854 
    855     COMPtr<IWebFramePrivate> framePrivate(Query, frame);
    856     if (!framePrivate)
    857         return false;
    858 
    859     BSTR nameBSTR = JSStringCopyBSTR(animationName);
    860     BOOL wasRunning = FALSE;
    861     hr = framePrivate->pauseAnimation(nameBSTR, element.get(), time, &wasRunning);
    862     SysFreeString(nameBSTR);
    863 
    864     return SUCCEEDED(hr) && wasRunning;
    865 }
    866 
    867 bool LayoutTestController::pauseTransitionAtTimeOnElementWithId(JSStringRef propertyName, double time, JSStringRef elementId)
    868 {
    869     COMPtr<IDOMDocument> document;
    870     if (FAILED(frame->DOMDocument(&document)))
    871         return false;
    872 
    873     BSTR idBSTR = JSStringCopyBSTR(elementId);
    874     COMPtr<IDOMElement> element;
    875     HRESULT hr = document->getElementById(idBSTR, &element);
    876     SysFreeString(idBSTR);
    877     if (FAILED(hr))
    878         return false;
    879 
    880     COMPtr<IWebFramePrivate> framePrivate(Query, frame);
    881     if (!framePrivate)
    882         return false;
    883 
    884     BSTR nameBSTR = JSStringCopyBSTR(propertyName);
    885     BOOL wasRunning = FALSE;
    886     hr = framePrivate->pauseTransition(nameBSTR, element.get(), time, &wasRunning);
    887     SysFreeString(nameBSTR);
    888 
    889     return SUCCEEDED(hr) && wasRunning;
    890 }
    891 
    892 bool LayoutTestController::sampleSVGAnimationForElementAtTime(JSStringRef animationId, double time, JSStringRef elementId)
    893 {
    894     COMPtr<IDOMDocument> document;
    895     if (FAILED(frame->DOMDocument(&document)))
    896         return false;
    897 
    898     BSTR idBSTR = JSStringCopyBSTR(animationId);
    899     COMPtr<IDOMElement> element;
    900     HRESULT hr = document->getElementById(idBSTR, &element);
    901     SysFreeString(idBSTR);
    902     if (FAILED(hr))
    903         return false;
    904 
    905     COMPtr<IWebFramePrivate> framePrivate(Query, frame);
    906     if (!framePrivate)
    907         return false;
    908 
    909     BSTR elementIdBSTR = JSStringCopyBSTR(elementId);
    910     BOOL wasRunning = FALSE;
    911     hr = framePrivate->pauseSVGAnimation(elementIdBSTR, element.get(), time, &wasRunning);
    912     SysFreeString(elementIdBSTR);
    913 
    914     return SUCCEEDED(hr) && wasRunning;
    915 }
    916 
    917 unsigned LayoutTestController::numberOfActiveAnimations() const
    918 {
    919     COMPtr<IWebFramePrivate> framePrivate(Query, frame);
    920     if (!framePrivate)
    921         return 0;
    922 
    923     UINT number = 0;
    924     if (FAILED(framePrivate->numberOfActiveAnimations(&number)))
    925         return 0;
    926 
    927     return number;
    928 }
    929 
    930 static _bstr_t bstrT(JSStringRef jsString)
    931 {
    932     // The false parameter tells the _bstr_t constructor to adopt the BSTR we pass it.
    933     return _bstr_t(JSStringCopyBSTR(jsString), false);
    934 }
    935 
    936 void LayoutTestController::whiteListAccessFromOrigin(JSStringRef sourceOrigin, JSStringRef destinationProtocol, JSStringRef destinationHost, bool allowDestinationSubdomains)
    937 {
    938     COMPtr<IWebViewPrivate> webView;
    939     if (FAILED(WebKitCreateInstance(__uuidof(WebView), 0, __uuidof(webView), reinterpret_cast<void**>(&webView))))
    940         return;
    941 
    942     webView->whiteListAccessFromOrigin(bstrT(sourceOrigin).GetBSTR(), bstrT(destinationProtocol).GetBSTR(), bstrT(destinationHost).GetBSTR(), allowDestinationSubdomains);
    943 }
    944 
    945 void LayoutTestController::addUserScript(JSStringRef source, bool runAtStart)
    946 {
    947     COMPtr<IWebViewPrivate> webView;
    948     if (FAILED(WebKitCreateInstance(__uuidof(WebView), 0, __uuidof(webView), reinterpret_cast<void**>(&webView))))
    949         return;
    950 
    951     COMPtr<IWebScriptWorld> world;
    952     if (FAILED(WebKitCreateInstance(__uuidof(WebScriptWorld), 0, __uuidof(world), reinterpret_cast<void**>(&world))))
    953         return;
    954 
    955     webView->addUserScriptToGroup(_bstr_t(L"org.webkit.DumpRenderTree").GetBSTR(), world.get(), bstrT(source).GetBSTR(), 0, 0, 0, 0, 0, runAtStart ? WebInjectAtDocumentStart : WebInjectAtDocumentEnd);
    956 }
    957 
    958 
    959 void LayoutTestController::addUserStyleSheet(JSStringRef source)
    960 {
    961     COMPtr<IWebViewPrivate> webView;
    962     if (FAILED(WebKitCreateInstance(__uuidof(WebView), 0, __uuidof(webView), reinterpret_cast<void**>(&webView))))
    963         return;
    964 
    965     COMPtr<IWebScriptWorld> world;
    966     if (FAILED(WebKitCreateInstance(__uuidof(WebScriptWorld), 0, __uuidof(world), reinterpret_cast<void**>(&world))))
    967         return;
    968 
    969     webView->addUserStyleSheetToGroup(_bstr_t(L"org.webkit.DumpRenderTree").GetBSTR(), world.get(), bstrT(source).GetBSTR(), 0, 0, 0, 0, 0);
    970 }
    971 
    972 void LayoutTestController::showWebInspector()
    973 {
    974     COMPtr<IWebView> webView;
    975     if (FAILED(frame->webView(&webView)))
    976         return;
    977 
    978     COMPtr<IWebPreferences> preferences;
    979     if (FAILED(webView->preferences(&preferences)))
    980         return;
    981 
    982     COMPtr<IWebPreferencesPrivate> prefsPrivate(Query, preferences);
    983     if (!prefsPrivate)
    984         return;
    985 
    986     prefsPrivate->setDeveloperExtrasEnabled(true);
    987 
    988     COMPtr<IWebViewPrivate> viewPrivate(Query, webView);
    989     if (!viewPrivate)
    990         return;
    991 
    992     COMPtr<IWebInspector> inspector;
    993     if (SUCCEEDED(viewPrivate->inspector(&inspector)))
    994         inspector->show();
    995 }
    996 
    997 void LayoutTestController::closeWebInspector()
    998 {
    999     COMPtr<IWebView> webView;
   1000     if (FAILED(frame->webView(&webView)))
   1001         return;
   1002 
   1003     COMPtr<IWebViewPrivate> viewPrivate(Query, webView);
   1004     if (!viewPrivate)
   1005         return;
   1006 
   1007     COMPtr<IWebInspector> inspector;
   1008     if (FAILED(viewPrivate->inspector(&inspector)))
   1009         return;
   1010 
   1011     inspector->close();
   1012 
   1013     COMPtr<IWebPreferences> preferences;
   1014     if (FAILED(webView->preferences(&preferences)))
   1015         return;
   1016 
   1017     COMPtr<IWebPreferencesPrivate> prefsPrivate(Query, preferences);
   1018     if (!prefsPrivate)
   1019         return;
   1020 
   1021     prefsPrivate->setDeveloperExtrasEnabled(false);
   1022 }
   1023 
   1024 void LayoutTestController::evaluateInWebInspector(long callId, JSStringRef script)
   1025 {
   1026     COMPtr<IWebView> webView;
   1027     if (FAILED(frame->webView(&webView)))
   1028         return;
   1029 
   1030     COMPtr<IWebViewPrivate> viewPrivate(Query, webView);
   1031     if (!viewPrivate)
   1032         return;
   1033 
   1034     COMPtr<IWebInspector> inspector;
   1035     if (FAILED(viewPrivate->inspector(&inspector)))
   1036         return;
   1037 
   1038     COMPtr<IWebInspectorPrivate> inspectorPrivate(Query, inspector);
   1039     if (!inspectorPrivate)
   1040         return;
   1041 
   1042     inspectorPrivate->evaluateInFrontend(callId, bstrT(script).GetBSTR());
   1043 }
   1044 
   1045 typedef HashMap<unsigned, COMPtr<IWebScriptWorld> > WorldMap;
   1046 static WorldMap& worldMap()
   1047 {
   1048     static WorldMap& map = *new WorldMap;
   1049     return map;
   1050 }
   1051 
   1052 unsigned worldIDForWorld(IWebScriptWorld* world)
   1053 {
   1054     WorldMap::const_iterator end = worldMap().end();
   1055     for (WorldMap::const_iterator it = worldMap().begin(); it != end; ++it) {
   1056         if (it->second == world)
   1057             return it->first;
   1058     }
   1059 
   1060     return 0;
   1061 }
   1062 
   1063 void LayoutTestController::evaluateScriptInIsolatedWorld(unsigned worldID, JSObjectRef globalObject, JSStringRef script)
   1064 {
   1065     COMPtr<IWebFramePrivate> framePrivate(Query, frame);
   1066     if (!framePrivate)
   1067         return;
   1068 
   1069     // A worldID of 0 always corresponds to a new world. Any other worldID corresponds to a world
   1070     // that is created once and cached forever.
   1071     COMPtr<IWebScriptWorld> world;
   1072     if (!worldID) {
   1073         if (FAILED(WebKitCreateInstance(__uuidof(WebScriptWorld), 0, __uuidof(world), reinterpret_cast<void**>(&world))))
   1074             return;
   1075     } else {
   1076         COMPtr<IWebScriptWorld>& worldSlot = worldMap().add(worldID, 0).first->second;
   1077         if (!worldSlot && FAILED(WebKitCreateInstance(__uuidof(WebScriptWorld), 0, __uuidof(worldSlot), reinterpret_cast<void**>(&worldSlot))))
   1078             return;
   1079         world = worldSlot;
   1080     }
   1081 
   1082     BSTR result;
   1083     if (FAILED(framePrivate->stringByEvaluatingJavaScriptInScriptWorld(world.get(), globalObject, bstrT(script).GetBSTR(), &result)))
   1084         return;
   1085     SysFreeString(result);
   1086 }
   1087 
   1088 void LayoutTestController::removeAllVisitedLinks()
   1089 {
   1090     COMPtr<IWebHistory> history;
   1091     if (FAILED(WebKitCreateInstance(CLSID_WebHistory, 0, __uuidof(history), reinterpret_cast<void**>(&history))))
   1092         return;
   1093 
   1094     COMPtr<IWebHistory> sharedHistory;
   1095     if (FAILED(history->optionalSharedHistory(&sharedHistory)) || !sharedHistory)
   1096         return;
   1097 
   1098     COMPtr<IWebHistoryPrivate> sharedHistoryPrivate;
   1099     if (FAILED(sharedHistory->QueryInterface(&sharedHistoryPrivate)))
   1100         return;
   1101 
   1102     sharedHistoryPrivate->removeAllVisitedLinks();
   1103 }
   1104 
   1105 JSRetainPtr<JSStringRef> LayoutTestController::counterValueForElementById(JSStringRef id)
   1106 {
   1107     COMPtr<IWebFramePrivate> framePrivate(Query, frame);
   1108     if (!framePrivate)
   1109         return 0;
   1110 
   1111     wstring idWstring = jsStringRefToWString(id);
   1112     BSTR idBSTR = SysAllocStringLen((OLECHAR*)idWstring.c_str(), idWstring.length());
   1113     BSTR counterValueBSTR;
   1114     if (FAILED(framePrivate->counterValueForElementById(idBSTR, &counterValueBSTR)))
   1115         return 0;
   1116 
   1117     wstring counterValue(counterValueBSTR, SysStringLen(counterValueBSTR));
   1118     SysFreeString(idBSTR);
   1119     SysFreeString(counterValueBSTR);
   1120     JSRetainPtr<JSStringRef> counterValueJS(Adopt, JSStringCreateWithCharacters(counterValue.data(), counterValue.length()));
   1121     return counterValueJS;
   1122 }
   1123 
   1124 int LayoutTestController::pageNumberForElementById(JSStringRef, float, float)
   1125 {
   1126     // FIXME: implement
   1127     return -1;
   1128 }
   1129 
   1130 int LayoutTestController::numberOfPages(float, float)
   1131 {
   1132     // FIXME: implement
   1133     return -1;
   1134 }
   1135