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