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