• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 <WebCore/COMPtr.h>
38 #include <wtf/Platform.h>
39 #include <wtf/RetainPtr.h>
40 #include <wtf/Vector.h>
41 #include <JavaScriptCore/Assertions.h>
42 #include <JavaScriptCore/JavaScriptCore.h>
43 #include <JavaScriptCore/JSRetainPtr.h>
44 #include <JavaScriptCore/JSStringRefBSTR.h>
45 #include <WebKit/WebKit.h>
46 #include <WebKit/WebKitCOMAPI.h>
47 #include <string>
48 #include <CoreFoundation/CoreFoundation.h>
49 #include <shlwapi.h>
50 #include <shlguid.h>
51 #include <shobjidl.h>
52 
53 using std::string;
54 using std::wstring;
55 
56 static bool resolveCygwinPath(const wstring& cygwinPath, wstring& windowsPath);
57 
~LayoutTestController()58 LayoutTestController::~LayoutTestController()
59 {
60     COMPtr<IWebView> webView;
61     if (FAILED(frame->webView(&webView)))
62         return;
63 
64     // reset webview-related states back to default values in preparation for next test
65 
66     COMPtr<IWebViewPrivate> viewPrivate;
67     if (SUCCEEDED(webView->QueryInterface(&viewPrivate)))
68         viewPrivate->setTabKeyCyclesThroughElements(TRUE);
69 
70     COMPtr<IWebViewEditing> viewEditing;
71     if (FAILED(webView->QueryInterface(&viewEditing)))
72         return;
73     COMPtr<IWebEditingDelegate> delegate;
74     if (FAILED(viewEditing->editingDelegate(&delegate)))
75         return;
76     COMPtr<EditingDelegate> editingDelegate(Query, viewEditing.get());
77     if (editingDelegate)
78         editingDelegate->setAcceptsEditing(TRUE);
79 }
80 
addDisallowedURL(JSStringRef url)81 void LayoutTestController::addDisallowedURL(JSStringRef url)
82 {
83     // FIXME: Implement!
84 }
85 
clearBackForwardList()86 void LayoutTestController::clearBackForwardList()
87 {
88     COMPtr<IWebView> webView;
89     if (FAILED(frame->webView(&webView)))
90         return;
91 
92     COMPtr<IWebBackForwardList> backForwardList;
93     if (FAILED(webView->backForwardList(&backForwardList)))
94         return;
95 
96     COMPtr<IWebHistoryItem> item;
97     if (FAILED(backForwardList->currentItem(&item)))
98         return;
99 
100     // We clear the history by setting the back/forward list's capacity to 0
101     // then restoring it back and adding back the current item.
102     int capacity;
103     if (FAILED(backForwardList->capacity(&capacity)))
104         return;
105 
106     backForwardList->setCapacity(0);
107     backForwardList->setCapacity(capacity);
108     backForwardList->addItem(item.get());
109     backForwardList->goToItem(item.get());
110 }
111 
copyDecodedHostName(JSStringRef name)112 JSStringRef LayoutTestController::copyDecodedHostName(JSStringRef name)
113 {
114     // FIXME: Implement!
115     return 0;
116 }
117 
copyEncodedHostName(JSStringRef name)118 JSStringRef LayoutTestController::copyEncodedHostName(JSStringRef name)
119 {
120     // FIXME: Implement!
121     return 0;
122 }
123 
disableImageLoading()124 void LayoutTestController::disableImageLoading()
125 {
126     COMPtr<IWebView> webView;
127     if (FAILED(frame->webView(&webView)))
128         return;
129 
130     COMPtr<IWebPreferences> preferences;
131     if (FAILED(webView->preferences(&preferences)))
132         return;
133 
134     preferences->setLoadsImagesAutomatically(FALSE);
135 }
136 
dispatchPendingLoadRequests()137 void LayoutTestController::dispatchPendingLoadRequests()
138 {
139     // FIXME: Implement for testing fix for 6727495
140 }
141 
display()142 void LayoutTestController::display()
143 {
144     displayWebView();
145 }
146 
keepWebHistory()147 void LayoutTestController::keepWebHistory()
148 {
149     COMPtr<IWebHistory> history;
150     if (FAILED(WebKitCreateInstance(CLSID_WebHistory, 0, __uuidof(history), reinterpret_cast<void**>(&history))))
151         return;
152 
153     COMPtr<IWebHistory> sharedHistory;
154     if (FAILED(WebKitCreateInstance(CLSID_WebHistory, 0, __uuidof(sharedHistory), reinterpret_cast<void**>(&sharedHistory))))
155         return;
156 
157     history->setOptionalSharedHistory(sharedHistory.get());
158 }
159 
waitForPolicyDelegate()160 void LayoutTestController::waitForPolicyDelegate()
161 {
162     // FIXME: Implement this.
163 }
164 
webHistoryItemCount()165 size_t LayoutTestController::webHistoryItemCount()
166 {
167     COMPtr<IWebHistory> history;
168     if (FAILED(WebKitCreateInstance(CLSID_WebHistory, 0, __uuidof(history), reinterpret_cast<void**>(&history))))
169         return 0;
170 
171     COMPtr<IWebHistory> sharedHistory;
172     if (FAILED(history->optionalSharedHistory(&sharedHistory)) || !sharedHistory)
173         return 0;
174 
175     COMPtr<IWebHistoryPrivate> sharedHistoryPrivate;
176     if (FAILED(sharedHistory->QueryInterface(&sharedHistoryPrivate)))
177         return 0;
178 
179     int count;
180     if (FAILED(sharedHistoryPrivate->allItems(&count, 0)))
181         return 0;
182 
183     return count;
184 }
185 
notifyDone()186 void LayoutTestController::notifyDone()
187 {
188     // Same as on mac.  This can be shared.
189     if (m_waitToDump && !topLoadingFrame && !WorkQueue::shared()->count())
190         dump();
191     m_waitToDump = false;
192 }
193 
pathToLocalResource(JSContextRef context,JSStringRef url)194 JSStringRef LayoutTestController::pathToLocalResource(JSContextRef context, JSStringRef url)
195 {
196     wstring input(JSStringGetCharactersPtr(url), JSStringGetLength(url));
197 
198     wstring localPath;
199     if (!resolveCygwinPath(input, localPath)) {
200         printf("ERROR: Failed to resolve Cygwin path %S\n", input.c_str());
201         return 0;
202     }
203 
204     return JSStringCreateWithCharacters(localPath.c_str(), localPath.length());
205 }
206 
jsStringRefToWString(JSStringRef jsStr)207 static wstring jsStringRefToWString(JSStringRef jsStr)
208 {
209     size_t length = JSStringGetLength(jsStr);
210     Vector<WCHAR> buffer(length + 1);
211     memcpy(buffer.data(), JSStringGetCharactersPtr(jsStr), length * sizeof(WCHAR));
212     buffer[length] = '\0';
213 
214     return buffer.data();
215 }
216 
queueLoad(JSStringRef url,JSStringRef target)217 void LayoutTestController::queueLoad(JSStringRef url, JSStringRef target)
218 {
219     COMPtr<IWebDataSource> dataSource;
220     if (FAILED(frame->dataSource(&dataSource)))
221         return;
222 
223     COMPtr<IWebURLResponse> response;
224     if (FAILED(dataSource->response(&response)) || !response)
225         return;
226 
227     BSTR responseURLBSTR;
228     if (FAILED(response->URL(&responseURLBSTR)))
229         return;
230     wstring responseURL(responseURLBSTR, SysStringLen(responseURLBSTR));
231     SysFreeString(responseURLBSTR);
232 
233     // FIXME: We should do real relative URL resolution here.
234     int lastSlash = responseURL.rfind('/');
235     if (lastSlash != -1)
236         responseURL = responseURL.substr(0, lastSlash);
237 
238     wstring wURL = jsStringRefToWString(url);
239     wstring wAbsoluteURL = responseURL + TEXT("/") + wURL;
240     JSRetainPtr<JSStringRef> jsAbsoluteURL(Adopt, JSStringCreateWithCharacters(wAbsoluteURL.data(), wAbsoluteURL.length()));
241 
242     WorkQueue::shared()->queue(new LoadItem(jsAbsoluteURL.get(), target));
243 }
244 
setAcceptsEditing(bool acceptsEditing)245 void LayoutTestController::setAcceptsEditing(bool acceptsEditing)
246 {
247     COMPtr<IWebView> webView;
248     if (FAILED(frame->webView(&webView)))
249         return;
250 
251     COMPtr<IWebViewEditing> viewEditing;
252     if (FAILED(webView->QueryInterface(&viewEditing)))
253         return;
254 
255     COMPtr<IWebEditingDelegate> delegate;
256     if (FAILED(viewEditing->editingDelegate(&delegate)))
257         return;
258 
259     EditingDelegate* editingDelegate = (EditingDelegate*)(IWebEditingDelegate*)delegate.get();
260     editingDelegate->setAcceptsEditing(acceptsEditing);
261 }
262 
setAuthorAndUserStylesEnabled(bool flag)263 void LayoutTestController::setAuthorAndUserStylesEnabled(bool flag)
264 {
265     COMPtr<IWebView> webView;
266     if (FAILED(frame->webView(&webView)))
267         return;
268 
269     COMPtr<IWebPreferences> preferences;
270     if (FAILED(webView->preferences(&preferences)))
271         return;
272 
273     COMPtr<IWebPreferencesPrivate> prefsPrivate(Query, preferences);
274     if (!prefsPrivate)
275         return;
276 
277     prefsPrivate->setAuthorAndUserStylesEnabled(flag);
278 }
279 
setCustomPolicyDelegate(bool setDelegate,bool permissive)280 void LayoutTestController::setCustomPolicyDelegate(bool setDelegate, bool permissive)
281 {
282     COMPtr<IWebView> webView;
283     if (FAILED(frame->webView(&webView)))
284         return;
285 
286     if (setDelegate) {
287         policyDelegate->setPermissive(permissive);
288         webView->setPolicyDelegate(policyDelegate);
289     } else
290         webView->setPolicyDelegate(0);
291 }
292 
setIconDatabaseEnabled(bool iconDatabaseEnabled)293 void LayoutTestController::setIconDatabaseEnabled(bool iconDatabaseEnabled)
294 {
295     // See also <rdar://problem/6480108>
296     COMPtr<IWebIconDatabase> iconDatabase;
297     COMPtr<IWebIconDatabase> tmpIconDatabase;
298     if (FAILED(WebKitCreateInstance(CLSID_WebIconDatabase, 0, IID_IWebIconDatabase, (void**)&tmpIconDatabase)))
299         return;
300     if (FAILED(tmpIconDatabase->sharedIconDatabase(&iconDatabase)))
301         return;
302 
303     iconDatabase->setEnabled(iconDatabaseEnabled);
304 }
305 
setMainFrameIsFirstResponder(bool flag)306 void LayoutTestController::setMainFrameIsFirstResponder(bool flag)
307 {
308     // FIXME: Implement!
309 }
310 
setPrivateBrowsingEnabled(bool privateBrowsingEnabled)311 void LayoutTestController::setPrivateBrowsingEnabled(bool privateBrowsingEnabled)
312 {
313     COMPtr<IWebView> webView;
314     if (FAILED(frame->webView(&webView)))
315         return;
316 
317     COMPtr<IWebPreferences> preferences;
318     if (FAILED(webView->preferences(&preferences)))
319         return;
320 
321     preferences->setPrivateBrowsingEnabled(privateBrowsingEnabled);
322 }
323 
setXSSAuditorEnabled(bool enabled)324 void LayoutTestController::setXSSAuditorEnabled(bool enabled)
325 {
326     COMPtr<IWebView> webView;
327     if (FAILED(frame->webView(&webView)))
328         return;
329 
330     COMPtr<IWebPreferences> preferences;
331     if (FAILED(webView->preferences(&preferences)))
332         return;
333 
334     COMPtr<IWebPreferencesPrivate> prefsPrivate(Query, preferences);
335     if (!prefsPrivate)
336         return;
337 
338     prefsPrivate->setXSSAuditorEnabled(enabled);
339 }
340 
setPopupBlockingEnabled(bool enabled)341 void LayoutTestController::setPopupBlockingEnabled(bool enabled)
342 {
343     COMPtr<IWebView> webView;
344     if (FAILED(frame->webView(&webView)))
345         return;
346 
347     COMPtr<IWebPreferences> preferences;
348     if (FAILED(webView->preferences(&preferences)))
349         return;
350 
351     preferences->setJavaScriptCanOpenWindowsAutomatically(!enabled);
352 }
353 
setTabKeyCyclesThroughElements(bool shouldCycle)354 void LayoutTestController::setTabKeyCyclesThroughElements(bool shouldCycle)
355 {
356     COMPtr<IWebView> webView;
357     if (FAILED(frame->webView(&webView)))
358         return;
359 
360     COMPtr<IWebViewPrivate> viewPrivate;
361     if (FAILED(webView->QueryInterface(&viewPrivate)))
362         return;
363 
364     viewPrivate->setTabKeyCyclesThroughElements(shouldCycle ? TRUE : FALSE);
365 }
366 
setUseDashboardCompatibilityMode(bool flag)367 void LayoutTestController::setUseDashboardCompatibilityMode(bool flag)
368 {
369     // FIXME: Implement!
370 }
371 
setUserStyleSheetEnabled(bool flag)372 void LayoutTestController::setUserStyleSheetEnabled(bool flag)
373 {
374     COMPtr<IWebView> webView;
375     if (FAILED(frame->webView(&webView)))
376         return;
377 
378     COMPtr<IWebPreferences> preferences;
379     if (FAILED(webView->preferences(&preferences)))
380         return;
381 
382    preferences->setUserStyleSheetEnabled(flag);
383 }
384 
appendComponentToPath(wstring & path,const wstring & component)385 bool appendComponentToPath(wstring& path, const wstring& component)
386 {
387     WCHAR buffer[MAX_PATH];
388 
389     if (path.size() + 1 > MAX_PATH)
390         return false;
391 
392     memcpy(buffer, path.data(), path.size() * sizeof(WCHAR));
393     buffer[path.size()] = '\0';
394 
395     if (!PathAppendW(buffer, component.c_str()))
396         return false;
397 
398     path = wstring(buffer);
399     return true;
400 }
401 
followShortcuts(wstring & path)402 static bool followShortcuts(wstring& path)
403 {
404     if (PathFileExists(path.c_str()))
405         return true;
406 
407     // Do we have a shortcut?
408     wstring linkPath = path;
409     linkPath.append(TEXT(".lnk"));
410     if (!PathFileExists(linkPath.c_str()))
411        return true;
412 
413     // We have a shortcut, find its target.
414     COMPtr<IShellLink> shortcut(Create, CLSID_ShellLink);
415     if (!shortcut)
416        return false;
417     COMPtr<IPersistFile> persistFile(Query, shortcut);
418     if (!shortcut)
419         return false;
420     if (FAILED(persistFile->Load(linkPath.c_str(), STGM_READ)))
421         return false;
422     if (FAILED(shortcut->Resolve(0, 0)))
423         return false;
424     WCHAR targetPath[MAX_PATH];
425     DWORD targetPathLen = _countof(targetPath);
426     if (FAILED(shortcut->GetPath(targetPath, targetPathLen, 0, 0)))
427         return false;
428     if (!PathFileExists(targetPath))
429         return false;
430     // Use the target path as the result path instead.
431     path = wstring(targetPath);
432 
433     return true;
434 }
435 
resolveCygwinPath(const wstring & cygwinPath,wstring & windowsPath)436 static bool resolveCygwinPath(const wstring& cygwinPath, wstring& windowsPath)
437 {
438     wstring fileProtocol = L"file://";
439     bool isFileProtocol = cygwinPath.find(fileProtocol) != string::npos;
440     if (cygwinPath[isFileProtocol ? 7 : 0] != '/')  // ensure path is absolute
441         return false;
442 
443     // Get the Root path.
444     WCHAR rootPath[MAX_PATH];
445     DWORD rootPathSize = _countof(rootPath);
446     DWORD keyType;
447     DWORD result = ::SHGetValueW(HKEY_LOCAL_MACHINE, TEXT("SOFTWARE\\Cygnus Solutions\\Cygwin\\mounts v2\\/"), TEXT("native"), &keyType, &rootPath, &rootPathSize);
448 
449     if (result != ERROR_SUCCESS || keyType != REG_SZ)
450         return false;
451 
452     windowsPath = wstring(rootPath, rootPathSize);
453 
454     int oldPos = isFileProtocol ? 8 : 1;
455     while (1) {
456         int newPos = cygwinPath.find('/', oldPos);
457 
458         if (newPos == -1) {
459             wstring pathComponent = cygwinPath.substr(oldPos);
460 
461             if (!appendComponentToPath(windowsPath, pathComponent))
462                return false;
463 
464             if (!followShortcuts(windowsPath))
465                 return false;
466 
467             break;
468         }
469 
470         wstring pathComponent = cygwinPath.substr(oldPos, newPos - oldPos);
471         if (!appendComponentToPath(windowsPath, pathComponent))
472             return false;
473 
474         if (!followShortcuts(windowsPath))
475             return false;
476 
477         oldPos = newPos + 1;
478     }
479 
480     if (isFileProtocol)
481         windowsPath = fileProtocol + windowsPath;
482 
483     return true;
484 }
485 
cfStringRefToWString(CFStringRef cfStr)486 static wstring cfStringRefToWString(CFStringRef cfStr)
487 {
488     Vector<wchar_t> v(CFStringGetLength(cfStr));
489     CFStringGetCharacters(cfStr, CFRangeMake(0, CFStringGetLength(cfStr)), (UniChar *)v.data());
490 
491     return wstring(v.data(), v.size());
492 }
493 
setUserStyleSheetLocation(JSStringRef jsURL)494 void LayoutTestController::setUserStyleSheetLocation(JSStringRef jsURL)
495 {
496     COMPtr<IWebView> webView;
497     if (FAILED(frame->webView(&webView)))
498         return;
499 
500     COMPtr<IWebPreferences> preferences;
501     if (FAILED(webView->preferences(&preferences)))
502         return;
503 
504     RetainPtr<CFStringRef> urlString(AdoptCF, JSStringCopyCFString(0, jsURL));
505     RetainPtr<CFURLRef> url(AdoptCF, CFURLCreateWithString(0, urlString.get(), 0));
506     if (!url)
507         return;
508 
509     // Now copy the file system path, POSIX style.
510     RetainPtr<CFStringRef> pathCF(AdoptCF, CFURLCopyFileSystemPath(url.get(), kCFURLPOSIXPathStyle));
511     if (!pathCF)
512         return;
513 
514     wstring path = cfStringRefToWString(pathCF.get());
515 
516     wstring resultPath;
517     if (!resolveCygwinPath(path, resultPath))
518         return;
519 
520     // The path has been resolved, now convert it back to a CFURL.
521     int result = WideCharToMultiByte(CP_UTF8, 0, resultPath.c_str(), resultPath.size() + 1, 0, 0, 0, 0);
522     Vector<char> utf8Vector(result);
523     result = WideCharToMultiByte(CP_UTF8, 0, resultPath.c_str(), resultPath.size() + 1, utf8Vector.data(), result, 0, 0);
524     if (!result)
525         return;
526 
527     url = CFURLCreateFromFileSystemRepresentation(0, (const UInt8*)utf8Vector.data(), utf8Vector.size() - 1, false);
528     if (!url)
529         return;
530 
531     resultPath = cfStringRefToWString(CFURLGetString(url.get()));
532 
533     BSTR resultPathBSTR = SysAllocStringLen(resultPath.data(), resultPath.size());
534     preferences->setUserStyleSheetLocation(resultPathBSTR);
535     SysFreeString(resultPathBSTR);
536 }
537 
setPersistentUserStyleSheetLocation(JSStringRef jsURL)538 void LayoutTestController::setPersistentUserStyleSheetLocation(JSStringRef jsURL)
539 {
540     RetainPtr<CFStringRef> urlString(AdoptCF, JSStringCopyCFString(0, jsURL));
541     ::setPersistentUserStyleSheetLocation(urlString.get());
542 }
543 
clearPersistentUserStyleSheet()544 void LayoutTestController::clearPersistentUserStyleSheet()
545 {
546     ::setPersistentUserStyleSheetLocation(0);
547 }
548 
setWindowIsKey(bool flag)549 void LayoutTestController::setWindowIsKey(bool flag)
550 {
551     COMPtr<IWebView> webView;
552     if (FAILED(frame->webView(&webView)))
553         return;
554 
555     COMPtr<IWebViewPrivate> viewPrivate;
556     if (FAILED(webView->QueryInterface(&viewPrivate)))
557         return;
558 
559     HWND webViewWindow;
560     if (FAILED(viewPrivate->viewWindow((OLE_HANDLE*)&webViewWindow)))
561         return;
562 
563     ::SendMessage(webViewWindow, flag ? WM_SETFOCUS : WM_KILLFOCUS, (WPARAM)::GetDesktopWindow(), 0);
564 }
565 
setSmartInsertDeleteEnabled(bool flag)566 void LayoutTestController::setSmartInsertDeleteEnabled(bool flag)
567 {
568     COMPtr<IWebView> webView;
569     if (FAILED(frame->webView(&webView)))
570         return;
571 
572     COMPtr<IWebViewEditing> viewEditing;
573     if (FAILED(webView->QueryInterface(&viewEditing)))
574         return;
575 
576     viewEditing->setSmartInsertDeleteEnabled(flag ? TRUE : FALSE);
577 }
578 
setJavaScriptProfilingEnabled(bool flag)579 void LayoutTestController::setJavaScriptProfilingEnabled(bool flag)
580 {
581     COMPtr<IWebView> webView;
582     if (FAILED(frame->webView(&webView)))
583         return;
584 
585     COMPtr<IWebViewPrivate> viewPrivate;
586     if (FAILED(webView->QueryInterface(&viewPrivate)))
587         return;
588 
589     COMPtr<IWebPreferences> preferences;
590     if (FAILED(webView->preferences(&preferences)))
591         return;
592 
593     COMPtr<IWebPreferencesPrivate> prefsPrivate(Query, preferences);
594     if (!prefsPrivate)
595         return;
596 
597     COMPtr<IWebInspector> inspector;
598     if (FAILED(viewPrivate->inspector(&inspector)))
599         return;
600 
601     prefsPrivate->setDeveloperExtrasEnabled(flag);
602     inspector->setJavaScriptProfilingEnabled(flag);
603 }
604 
setSelectTrailingWhitespaceEnabled(bool flag)605 void LayoutTestController::setSelectTrailingWhitespaceEnabled(bool flag)
606 {
607     COMPtr<IWebView> webView;
608     if (FAILED(frame->webView(&webView)))
609         return;
610 
611     COMPtr<IWebViewEditing> viewEditing;
612     if (FAILED(webView->QueryInterface(&viewEditing)))
613         return;
614 
615     viewEditing->setSelectTrailingWhitespaceEnabled(flag ? TRUE : FALSE);
616 }
617 
618 static const CFTimeInterval waitToDumpWatchdogInterval = 10.0;
619 
waitUntilDoneWatchdogFired(HWND,UINT,UINT_PTR,DWORD)620 static void CALLBACK waitUntilDoneWatchdogFired(HWND, UINT, UINT_PTR, DWORD)
621 {
622     const char* message = "FAIL: Timed out waiting for notifyDone to be called\n";
623     fprintf(stderr, message);
624     fprintf(stdout, message);
625     dump();
626 }
627 
setWaitToDump(bool waitUntilDone)628 void LayoutTestController::setWaitToDump(bool waitUntilDone)
629 {
630     m_waitToDump = waitUntilDone;
631     if (m_waitToDump && !waitToDumpWatchdog)
632         waitToDumpWatchdog = SetTimer(0, 0, waitToDumpWatchdogInterval * 1000, waitUntilDoneWatchdogFired);
633 }
634 
windowCount()635 int LayoutTestController::windowCount()
636 {
637     return openWindows().size();
638 }
639 
elementDoesAutoCompleteForElementWithId(JSStringRef id)640 bool LayoutTestController::elementDoesAutoCompleteForElementWithId(JSStringRef id)
641 {
642     COMPtr<IDOMDocument> document;
643     if (FAILED(frame->DOMDocument(&document)))
644         return false;
645 
646     wstring idWstring = jsStringRefToWString(id);
647     BSTR idBSTR = SysAllocStringLen((OLECHAR*)idWstring.c_str(), idWstring.length());
648     COMPtr<IDOMElement> element;
649     HRESULT result = document->getElementById(idBSTR, &element);
650     SysFreeString(idBSTR);
651 
652     if (FAILED(result))
653         return false;
654 
655     COMPtr<IWebFramePrivate> framePrivate(Query, frame);
656     if (!framePrivate)
657         return false;
658 
659     BOOL autoCompletes;
660     if (FAILED(framePrivate->elementDoesAutoComplete(element.get(), &autoCompletes)))
661         return false;
662 
663     return autoCompletes;
664 }
665 
execCommand(JSStringRef name,JSStringRef value)666 void LayoutTestController::execCommand(JSStringRef name, JSStringRef value)
667 {
668     wstring wName = jsStringRefToWString(name);
669     wstring wValue = jsStringRefToWString(value);
670 
671     COMPtr<IWebView> webView;
672     if (FAILED(frame->webView(&webView)))
673         return;
674 
675     COMPtr<IWebViewPrivate> viewPrivate;
676     if (FAILED(webView->QueryInterface(&viewPrivate)))
677         return;
678 
679     BSTR nameBSTR = SysAllocStringLen((OLECHAR*)wName.c_str(), wName.length());
680     BSTR valueBSTR = SysAllocStringLen((OLECHAR*)wValue.c_str(), wValue.length());
681     viewPrivate->executeCoreCommandByName(nameBSTR, valueBSTR);
682 
683     SysFreeString(nameBSTR);
684     SysFreeString(valueBSTR);
685 }
686 
setCacheModel(int)687 void LayoutTestController::setCacheModel(int)
688 {
689     // FIXME: Implement
690 }
691 
isCommandEnabled(JSStringRef)692 bool LayoutTestController::isCommandEnabled(JSStringRef /*name*/)
693 {
694     printf("ERROR: LayoutTestController::isCommandEnabled() not implemented\n");
695     return false;
696 }
697 
clearAllDatabases()698 void LayoutTestController::clearAllDatabases()
699 {
700     COMPtr<IWebDatabaseManager> databaseManager;
701     COMPtr<IWebDatabaseManager> tmpDatabaseManager;
702     if (FAILED(WebKitCreateInstance(CLSID_WebDatabaseManager, 0, IID_IWebDatabaseManager, (void**)&tmpDatabaseManager)))
703         return;
704     if (FAILED(tmpDatabaseManager->sharedWebDatabaseManager(&databaseManager)))
705         return;
706 
707     databaseManager->deleteAllDatabases();
708 }
709 
setDatabaseQuota(unsigned long long quota)710 void LayoutTestController::setDatabaseQuota(unsigned long long quota)
711 {
712     printf("ERROR: LayoutTestController::setDatabaseQuota() not implemented\n");
713 }
714 
setAppCacheMaximumSize(unsigned long long size)715 void LayoutTestController::setAppCacheMaximumSize(unsigned long long size)
716 {
717     printf("ERROR: LayoutTestController::setAppCacheMaximumSize() not implemented\n");
718 }
719 
pauseAnimationAtTimeOnElementWithId(JSStringRef animationName,double time,JSStringRef elementId)720 bool LayoutTestController::pauseAnimationAtTimeOnElementWithId(JSStringRef animationName, double time, JSStringRef elementId)
721 {
722     COMPtr<IDOMDocument> document;
723     if (FAILED(frame->DOMDocument(&document)))
724         return false;
725 
726     BSTR idBSTR = JSStringCopyBSTR(elementId);
727     COMPtr<IDOMElement> element;
728     HRESULT hr = document->getElementById(idBSTR, &element);
729     SysFreeString(idBSTR);
730     if (FAILED(hr))
731         return false;
732 
733     COMPtr<IWebFramePrivate> framePrivate(Query, frame);
734     if (!framePrivate)
735         return false;
736 
737     BSTR nameBSTR = JSStringCopyBSTR(animationName);
738     BOOL wasRunning = FALSE;
739     hr = framePrivate->pauseAnimation(nameBSTR, element.get(), time, &wasRunning);
740     SysFreeString(nameBSTR);
741 
742     return SUCCEEDED(hr) && wasRunning;
743 }
744 
pauseTransitionAtTimeOnElementWithId(JSStringRef propertyName,double time,JSStringRef elementId)745 bool LayoutTestController::pauseTransitionAtTimeOnElementWithId(JSStringRef propertyName, double time, JSStringRef elementId)
746 {
747     COMPtr<IDOMDocument> document;
748     if (FAILED(frame->DOMDocument(&document)))
749         return false;
750 
751     BSTR idBSTR = JSStringCopyBSTR(elementId);
752     COMPtr<IDOMElement> element;
753     HRESULT hr = document->getElementById(idBSTR, &element);
754     SysFreeString(idBSTR);
755     if (FAILED(hr))
756         return false;
757 
758     COMPtr<IWebFramePrivate> framePrivate(Query, frame);
759     if (!framePrivate)
760         return false;
761 
762     BSTR nameBSTR = JSStringCopyBSTR(propertyName);
763     BOOL wasRunning = FALSE;
764     hr = framePrivate->pauseTransition(nameBSTR, element.get(), time, &wasRunning);
765     SysFreeString(nameBSTR);
766 
767     return SUCCEEDED(hr) && wasRunning;
768 }
769 
numberOfActiveAnimations() const770 unsigned LayoutTestController::numberOfActiveAnimations() const
771 {
772     COMPtr<IWebFramePrivate> framePrivate(Query, frame);
773     if (!framePrivate)
774         return 0;
775 
776     UINT number = 0;
777     if (FAILED(framePrivate->numberOfActiveAnimations(&number)))
778         return 0;
779 
780     return number;
781 }
782