1 /* 2 * Copyright (C) 2005, 2006, 2007, 2008 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 "UIDelegate.h" 31 32 #include "DumpRenderTree.h" 33 #include "DraggingInfo.h" 34 #include "EventSender.h" 35 #include "LayoutTestController.h" 36 #include "DRTDesktopNotificationPresenter.h" 37 38 #include <WebCore/COMPtr.h> 39 #include <wtf/Platform.h> 40 #include <wtf/Vector.h> 41 #include <JavaScriptCore/Assertions.h> 42 #include <JavaScriptCore/JavaScriptCore.h> 43 #include <WebKit/WebKit.h> 44 #include <stdio.h> 45 46 using std::wstring; 47 48 class DRTUndoObject { 49 public: 50 DRTUndoObject(IWebUndoTarget* target, BSTR actionName, IUnknown* obj) 51 : m_target(target) 52 , m_actionName(SysAllocString(actionName)) 53 , m_obj(obj) 54 { 55 } 56 57 ~DRTUndoObject() 58 { 59 SysFreeString(m_actionName); 60 } 61 62 void invoke() 63 { 64 m_target->invoke(m_actionName, m_obj.get()); 65 } 66 67 private: 68 IWebUndoTarget* m_target; 69 BSTR m_actionName; 70 COMPtr<IUnknown> m_obj; 71 }; 72 73 class DRTUndoStack { 74 public: 75 ~DRTUndoStack() { deleteAllValues(m_undoVector); } 76 77 bool isEmpty() const { return m_undoVector.isEmpty(); } 78 void clear() { deleteAllValues(m_undoVector); m_undoVector.clear(); } 79 80 void push(DRTUndoObject* undoObject) { m_undoVector.append(undoObject); } 81 DRTUndoObject* pop() { DRTUndoObject* top = m_undoVector.last(); m_undoVector.removeLast(); return top; } 82 83 private: 84 Vector<DRTUndoObject*> m_undoVector; 85 }; 86 87 class DRTUndoManager { 88 public: 89 DRTUndoManager(); 90 91 void removeAllActions(); 92 void registerUndoWithTarget(IWebUndoTarget* target, BSTR actionName, IUnknown* obj); 93 void redo(); 94 void undo(); 95 bool canRedo() { return !m_redoStack->isEmpty(); } 96 bool canUndo() { return !m_undoStack->isEmpty(); } 97 98 private: 99 OwnPtr<DRTUndoStack> m_redoStack; 100 OwnPtr<DRTUndoStack> m_undoStack; 101 bool m_isRedoing; 102 bool m_isUndoing; 103 }; 104 105 DRTUndoManager::DRTUndoManager() 106 : m_redoStack(new DRTUndoStack) 107 , m_undoStack(new DRTUndoStack) 108 , m_isRedoing(false) 109 , m_isUndoing(false) 110 { 111 } 112 113 void DRTUndoManager::removeAllActions() 114 { 115 m_redoStack->clear(); 116 m_undoStack->clear(); 117 } 118 119 void DRTUndoManager::registerUndoWithTarget(IWebUndoTarget* target, BSTR actionName, IUnknown* obj) 120 { 121 if (!m_isUndoing && !m_isRedoing) 122 m_redoStack->clear(); 123 124 DRTUndoStack* stack = m_isUndoing ? m_redoStack.get() : m_undoStack.get(); 125 stack->push(new DRTUndoObject(target, actionName, obj)); 126 } 127 128 void DRTUndoManager::redo() 129 { 130 if (!canRedo()) 131 return; 132 133 m_isRedoing = true; 134 135 DRTUndoObject* redoObject = m_redoStack->pop(); 136 redoObject->invoke(); 137 delete redoObject; 138 139 m_isRedoing = false; 140 } 141 142 void DRTUndoManager::undo() 143 { 144 if (!canUndo()) 145 return; 146 147 m_isUndoing = true; 148 149 DRTUndoObject* undoObject = m_undoStack->pop(); 150 undoObject->invoke(); 151 delete undoObject; 152 153 m_isUndoing = false; 154 } 155 156 UIDelegate::UIDelegate() 157 : m_refCount(1) 158 , m_undoManager(new DRTUndoManager) 159 , m_desktopNotifications(new DRTDesktopNotificationPresenter) 160 { 161 m_frame.bottom = 0; 162 m_frame.top = 0; 163 m_frame.left = 0; 164 m_frame.right = 0; 165 } 166 167 void UIDelegate::resetUndoManager() 168 { 169 m_undoManager.set(new DRTUndoManager); 170 } 171 172 HRESULT STDMETHODCALLTYPE UIDelegate::QueryInterface(REFIID riid, void** ppvObject) 173 { 174 *ppvObject = 0; 175 if (IsEqualGUID(riid, IID_IUnknown)) 176 *ppvObject = static_cast<IWebUIDelegate*>(this); 177 else if (IsEqualGUID(riid, IID_IWebUIDelegate)) 178 *ppvObject = static_cast<IWebUIDelegate*>(this); 179 else if (IsEqualGUID(riid, IID_IWebUIDelegate2)) 180 *ppvObject = static_cast<IWebUIDelegate2*>(this); 181 else if (IsEqualGUID(riid, IID_IWebUIDelegatePrivate)) 182 *ppvObject = static_cast<IWebUIDelegatePrivate*>(this); 183 else 184 return E_NOINTERFACE; 185 186 AddRef(); 187 return S_OK; 188 } 189 190 ULONG STDMETHODCALLTYPE UIDelegate::AddRef() 191 { 192 return ++m_refCount; 193 } 194 195 ULONG STDMETHODCALLTYPE UIDelegate::Release() 196 { 197 ULONG newRef = --m_refCount; 198 if (!newRef) 199 delete(this); 200 201 return newRef; 202 } 203 204 HRESULT STDMETHODCALLTYPE UIDelegate::hasCustomMenuImplementation( 205 /* [retval][out] */ BOOL *hasCustomMenus) 206 { 207 *hasCustomMenus = TRUE; 208 209 return S_OK; 210 } 211 212 HRESULT STDMETHODCALLTYPE UIDelegate::trackCustomPopupMenu( 213 /* [in] */ IWebView *sender, 214 /* [in] */ OLE_HANDLE menu, 215 /* [in] */ LPPOINT point) 216 { 217 // Do nothing 218 return S_OK; 219 } 220 221 HRESULT STDMETHODCALLTYPE UIDelegate::registerUndoWithTarget( 222 /* [in] */ IWebUndoTarget* target, 223 /* [in] */ BSTR actionName, 224 /* [in] */ IUnknown* actionArg) 225 { 226 m_undoManager->registerUndoWithTarget(target, actionName, actionArg); 227 return S_OK; 228 } 229 230 HRESULT STDMETHODCALLTYPE UIDelegate::removeAllActionsWithTarget( 231 /* [in] */ IWebUndoTarget*) 232 { 233 m_undoManager->removeAllActions(); 234 return S_OK; 235 } 236 237 HRESULT STDMETHODCALLTYPE UIDelegate::setActionTitle( 238 /* [in] */ BSTR actionTitle) 239 { 240 // It is not neccessary to implement this for DRT because there is 241 // menu to write out the title to. 242 return S_OK; 243 } 244 245 HRESULT STDMETHODCALLTYPE UIDelegate::undo() 246 { 247 m_undoManager->undo(); 248 return S_OK; 249 } 250 251 HRESULT STDMETHODCALLTYPE UIDelegate::redo() 252 { 253 m_undoManager->redo(); 254 return S_OK; 255 } 256 257 HRESULT STDMETHODCALLTYPE UIDelegate::canUndo( 258 /* [retval][out] */ BOOL* result) 259 { 260 if (!result) 261 return E_POINTER; 262 263 *result = m_undoManager->canUndo(); 264 return S_OK; 265 } 266 267 HRESULT STDMETHODCALLTYPE UIDelegate::canRedo( 268 /* [retval][out] */ BOOL* result) 269 { 270 if (!result) 271 return E_POINTER; 272 273 *result = m_undoManager->canRedo(); 274 return S_OK; 275 } 276 277 HRESULT STDMETHODCALLTYPE UIDelegate::printFrame( 278 /* [in] */ IWebView *webView, 279 /* [in] */ IWebFrame *frame) 280 { 281 return E_NOTIMPL; 282 } 283 284 HRESULT STDMETHODCALLTYPE UIDelegate::ftpDirectoryTemplatePath( 285 /* [in] */ IWebView *webView, 286 /* [retval][out] */ BSTR *path) 287 { 288 if (!path) 289 return E_POINTER; 290 *path = 0; 291 return E_NOTIMPL; 292 } 293 294 295 HRESULT STDMETHODCALLTYPE UIDelegate::webViewHeaderHeight( 296 /* [in] */ IWebView *webView, 297 /* [retval][out] */ float *result) 298 { 299 if (!result) 300 return E_POINTER; 301 *result = 0; 302 return E_NOTIMPL; 303 } 304 305 HRESULT STDMETHODCALLTYPE UIDelegate::webViewFooterHeight( 306 /* [in] */ IWebView *webView, 307 /* [retval][out] */ float *result) 308 { 309 if (!result) 310 return E_POINTER; 311 *result = 0; 312 return E_NOTIMPL; 313 } 314 315 HRESULT STDMETHODCALLTYPE UIDelegate::drawHeaderInRect( 316 /* [in] */ IWebView *webView, 317 /* [in] */ RECT *rect, 318 /* [in] */ OLE_HANDLE drawingContext) 319 { 320 return E_NOTIMPL; 321 } 322 323 HRESULT STDMETHODCALLTYPE UIDelegate::drawFooterInRect( 324 /* [in] */ IWebView *webView, 325 /* [in] */ RECT *rect, 326 /* [in] */ OLE_HANDLE drawingContext, 327 /* [in] */ UINT pageIndex, 328 /* [in] */ UINT pageCount) 329 { 330 return E_NOTIMPL; 331 } 332 333 HRESULT STDMETHODCALLTYPE UIDelegate::webViewPrintingMarginRect( 334 /* [in] */ IWebView *webView, 335 /* [retval][out] */ RECT *rect) 336 { 337 return E_NOTIMPL; 338 } 339 340 HRESULT STDMETHODCALLTYPE UIDelegate::canRunModal( 341 /* [in] */ IWebView *webView, 342 /* [retval][out] */ BOOL *canRunBoolean) 343 { 344 return E_NOTIMPL; 345 } 346 347 HRESULT STDMETHODCALLTYPE UIDelegate::createModalDialog( 348 /* [in] */ IWebView *sender, 349 /* [in] */ IWebURLRequest *request, 350 /* [retval][out] */ IWebView **newWebView) 351 { 352 return E_NOTIMPL; 353 } 354 355 HRESULT STDMETHODCALLTYPE UIDelegate::runModal( 356 /* [in] */ IWebView *webView) 357 { 358 return E_NOTIMPL; 359 } 360 361 HRESULT STDMETHODCALLTYPE UIDelegate::isMenuBarVisible( 362 /* [in] */ IWebView *webView, 363 /* [retval][out] */ BOOL *visible) 364 { 365 if (!visible) 366 return E_POINTER; 367 *visible = false; 368 return E_NOTIMPL; 369 } 370 371 HRESULT STDMETHODCALLTYPE UIDelegate::setMenuBarVisible( 372 /* [in] */ IWebView *webView, 373 /* [in] */ BOOL visible) 374 { 375 return E_NOTIMPL; 376 } 377 378 HRESULT STDMETHODCALLTYPE UIDelegate::runDatabaseSizeLimitPrompt( 379 /* [in] */ IWebView *webView, 380 /* [in] */ BSTR displayName, 381 /* [in] */ IWebFrame *initiatedByFrame, 382 /* [retval][out] */ BOOL *allowed) 383 { 384 if (!allowed) 385 return E_POINTER; 386 *allowed = false; 387 return E_NOTIMPL; 388 } 389 390 HRESULT STDMETHODCALLTYPE UIDelegate::paintCustomScrollbar( 391 /* [in] */ IWebView *webView, 392 /* [in] */ HDC hDC, 393 /* [in] */ RECT rect, 394 /* [in] */ WebScrollBarControlSize size, 395 /* [in] */ WebScrollbarControlState state, 396 /* [in] */ WebScrollbarControlPart pressedPart, 397 /* [in] */ BOOL vertical, 398 /* [in] */ float value, 399 /* [in] */ float proportion, 400 /* [in] */ WebScrollbarControlPartMask parts) 401 { 402 return E_NOTIMPL; 403 } 404 405 HRESULT STDMETHODCALLTYPE UIDelegate::paintCustomScrollCorner( 406 /* [in] */ IWebView *webView, 407 /* [in] */ HDC hDC, 408 /* [in] */ RECT rect) 409 { 410 return E_NOTIMPL; 411 } 412 413 HRESULT STDMETHODCALLTYPE UIDelegate::setFrame( 414 /* [in] */ IWebView* /*sender*/, 415 /* [in] */ RECT* frame) 416 { 417 m_frame = *frame; 418 return S_OK; 419 } 420 421 HRESULT STDMETHODCALLTYPE UIDelegate::webViewFrame( 422 /* [in] */ IWebView* /*sender*/, 423 /* [retval][out] */ RECT* frame) 424 { 425 *frame = m_frame; 426 return S_OK; 427 } 428 429 HRESULT STDMETHODCALLTYPE UIDelegate::runJavaScriptAlertPanelWithMessage( 430 /* [in] */ IWebView* /*sender*/, 431 /* [in] */ BSTR message) 432 { 433 printf("ALERT: %S\n", message ? message : L""); 434 435 return S_OK; 436 } 437 438 HRESULT STDMETHODCALLTYPE UIDelegate::runJavaScriptConfirmPanelWithMessage( 439 /* [in] */ IWebView* sender, 440 /* [in] */ BSTR message, 441 /* [retval][out] */ BOOL* result) 442 { 443 printf("CONFIRM: %S\n", message ? message : L""); 444 *result = TRUE; 445 446 return S_OK; 447 } 448 449 HRESULT STDMETHODCALLTYPE UIDelegate::runJavaScriptTextInputPanelWithPrompt( 450 /* [in] */ IWebView *sender, 451 /* [in] */ BSTR message, 452 /* [in] */ BSTR defaultText, 453 /* [retval][out] */ BSTR *result) 454 { 455 printf("PROMPT: %S, default text: %S\n", message ? message : L"", defaultText ? defaultText : L""); 456 *result = SysAllocString(defaultText); 457 458 return S_OK; 459 } 460 461 HRESULT STDMETHODCALLTYPE UIDelegate::runBeforeUnloadConfirmPanelWithMessage( 462 /* [in] */ IWebView* /*sender*/, 463 /* [in] */ BSTR /*message*/, 464 /* [in] */ IWebFrame* /*initiatedByFrame*/, 465 /* [retval][out] */ BOOL* result) 466 { 467 if (!result) 468 return E_POINTER; 469 *result = TRUE; 470 return E_NOTIMPL; 471 } 472 473 HRESULT STDMETHODCALLTYPE UIDelegate::webViewAddMessageToConsole( 474 /* [in] */ IWebView* sender, 475 /* [in] */ BSTR message, 476 /* [in] */ int lineNumber, 477 /* [in] */ BSTR url, 478 /* [in] */ BOOL isError) 479 { 480 wstring newMessage; 481 if (message) { 482 newMessage = message; 483 size_t fileProtocol = newMessage.find(L"file://"); 484 if (fileProtocol != wstring::npos) 485 newMessage = newMessage.substr(0, fileProtocol) + urlSuitableForTestResult(newMessage.substr(fileProtocol)); 486 } 487 488 printf("CONSOLE MESSAGE: line %d: %S\n", lineNumber, newMessage.c_str()); 489 return S_OK; 490 } 491 492 HRESULT STDMETHODCALLTYPE UIDelegate::doDragDrop( 493 /* [in] */ IWebView* sender, 494 /* [in] */ IDataObject* object, 495 /* [in] */ IDropSource* source, 496 /* [in] */ DWORD okEffect, 497 /* [retval][out] */ DWORD* performedEffect) 498 { 499 if (!performedEffect) 500 return E_POINTER; 501 502 *performedEffect = 0; 503 504 draggingInfo = new DraggingInfo(object, source); 505 HRESULT oleDragAndDropReturnValue = DRAGDROP_S_CANCEL; 506 replaySavedEvents(&oleDragAndDropReturnValue); 507 if (draggingInfo) { 508 *performedEffect = draggingInfo->performedDropEffect(); 509 delete draggingInfo; 510 draggingInfo = 0; 511 } 512 return oleDragAndDropReturnValue; 513 } 514 515 HRESULT STDMETHODCALLTYPE UIDelegate::webViewGetDlgCode( 516 /* [in] */ IWebView* /*sender*/, 517 /* [in] */ UINT /*keyCode*/, 518 /* [retval][out] */ LONG_PTR *code) 519 { 520 if (!code) 521 return E_POINTER; 522 *code = 0; 523 return E_NOTIMPL; 524 } 525 526 HRESULT STDMETHODCALLTYPE UIDelegate::createWebViewWithRequest( 527 /* [in] */ IWebView *sender, 528 /* [in] */ IWebURLRequest *request, 529 /* [retval][out] */ IWebView **newWebView) 530 { 531 if (!::gLayoutTestController->canOpenWindows()) 532 return E_FAIL; 533 *newWebView = createWebViewAndOffscreenWindow(); 534 return S_OK; 535 } 536 537 HRESULT STDMETHODCALLTYPE UIDelegate::webViewClose( 538 /* [in] */ IWebView *sender) 539 { 540 HWND hostWindow; 541 sender->hostWindow(reinterpret_cast<OLE_HANDLE*>(&hostWindow)); 542 DestroyWindow(hostWindow); 543 return S_OK; 544 } 545 546 HRESULT STDMETHODCALLTYPE UIDelegate::webViewFocus( 547 /* [in] */ IWebView *sender) 548 { 549 HWND hostWindow; 550 sender->hostWindow(reinterpret_cast<OLE_HANDLE*>(&hostWindow)); 551 SetForegroundWindow(hostWindow); 552 return S_OK; 553 } 554 555 HRESULT STDMETHODCALLTYPE UIDelegate::webViewUnfocus( 556 /* [in] */ IWebView *sender) 557 { 558 SetForegroundWindow(GetDesktopWindow()); 559 return S_OK; 560 } 561 562 HRESULT STDMETHODCALLTYPE UIDelegate::webViewPainted( 563 /* [in] */ IWebView *sender) 564 { 565 return S_OK; 566 } 567 568 HRESULT STDMETHODCALLTYPE UIDelegate::exceededDatabaseQuota( 569 /* [in] */ IWebView *sender, 570 /* [in] */ IWebFrame *frame, 571 /* [in] */ IWebSecurityOrigin *origin, 572 /* [in] */ BSTR databaseIdentifier) 573 { 574 BSTR protocol; 575 BSTR host; 576 unsigned short port; 577 578 origin->protocol(&protocol); 579 origin->host(&host); 580 origin->port(&port); 581 582 if (!done && gLayoutTestController->dumpDatabaseCallbacks()) 583 printf("UI DELEGATE DATABASE CALLBACK: exceededDatabaseQuotaForSecurityOrigin:{%S, %S, %i} database:%S\n", protocol, host, port, databaseIdentifier); 584 585 SysFreeString(protocol); 586 SysFreeString(host); 587 588 static const unsigned long long defaultQuota = 5 * 1024 * 1024; 589 origin->setQuota(defaultQuota); 590 591 return S_OK; 592 } 593 594 HRESULT STDMETHODCALLTYPE UIDelegate::embeddedViewWithArguments( 595 /* [in] */ IWebView *sender, 596 /* [in] */ IWebFrame *frame, 597 /* [in] */ IPropertyBag *arguments, 598 /* [retval][out] */ IWebEmbeddedView **view) 599 { 600 if (!view) 601 return E_POINTER; 602 *view = 0; 603 return E_NOTIMPL; 604 } 605 606 HRESULT STDMETHODCALLTYPE UIDelegate::webViewClosing( 607 /* [in] */ IWebView *sender) 608 { 609 return E_NOTIMPL; 610 } 611 612 HRESULT STDMETHODCALLTYPE UIDelegate::webViewSetCursor( 613 /* [in] */ IWebView *sender, 614 /* [in] */ OLE_HANDLE cursor) 615 { 616 return E_NOTIMPL; 617 } 618 619 HRESULT STDMETHODCALLTYPE UIDelegate::webViewDidInvalidate( 620 /* [in] */ IWebView *sender) 621 { 622 return E_NOTIMPL; 623 } 624 625 HRESULT STDMETHODCALLTYPE UIDelegate::setStatusText(IWebView*, BSTR text) 626 { 627 if (gLayoutTestController->dumpStatusCallbacks()) 628 printf("UI DELEGATE STATUS CALLBACK: setStatusText:%S\n", text ? text : L""); 629 return S_OK; 630 } 631 632 HRESULT STDMETHODCALLTYPE UIDelegate::desktopNotificationsDelegate(IWebDesktopNotificationsDelegate** result) 633 { 634 m_desktopNotifications.copyRefTo(result); 635 return S_OK; 636 } 637