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 if (IsEqualGUID(riid, IID_IWebUIDelegatePrivate2)) 184 *ppvObject = static_cast<IWebUIDelegatePrivate2*>(this); 185 else if (IsEqualGUID(riid, IID_IWebUIDelegatePrivate3)) 186 *ppvObject = static_cast<IWebUIDelegatePrivate3*>(this); 187 else 188 return E_NOINTERFACE; 189 190 AddRef(); 191 return S_OK; 192 } 193 194 ULONG STDMETHODCALLTYPE UIDelegate::AddRef() 195 { 196 return ++m_refCount; 197 } 198 199 ULONG STDMETHODCALLTYPE UIDelegate::Release() 200 { 201 ULONG newRef = --m_refCount; 202 if (!newRef) 203 delete(this); 204 205 return newRef; 206 } 207 208 HRESULT STDMETHODCALLTYPE UIDelegate::hasCustomMenuImplementation( 209 /* [retval][out] */ BOOL *hasCustomMenus) 210 { 211 *hasCustomMenus = TRUE; 212 213 return S_OK; 214 } 215 216 HRESULT STDMETHODCALLTYPE UIDelegate::trackCustomPopupMenu( 217 /* [in] */ IWebView *sender, 218 /* [in] */ OLE_HANDLE menu, 219 /* [in] */ LPPOINT point) 220 { 221 // Do nothing 222 return S_OK; 223 } 224 225 HRESULT STDMETHODCALLTYPE UIDelegate::registerUndoWithTarget( 226 /* [in] */ IWebUndoTarget* target, 227 /* [in] */ BSTR actionName, 228 /* [in] */ IUnknown* actionArg) 229 { 230 m_undoManager->registerUndoWithTarget(target, actionName, actionArg); 231 return S_OK; 232 } 233 234 HRESULT STDMETHODCALLTYPE UIDelegate::removeAllActionsWithTarget( 235 /* [in] */ IWebUndoTarget*) 236 { 237 m_undoManager->removeAllActions(); 238 return S_OK; 239 } 240 241 HRESULT STDMETHODCALLTYPE UIDelegate::setActionTitle( 242 /* [in] */ BSTR actionTitle) 243 { 244 // It is not neccessary to implement this for DRT because there is 245 // menu to write out the title to. 246 return S_OK; 247 } 248 249 HRESULT STDMETHODCALLTYPE UIDelegate::undo() 250 { 251 m_undoManager->undo(); 252 return S_OK; 253 } 254 255 HRESULT STDMETHODCALLTYPE UIDelegate::redo() 256 { 257 m_undoManager->redo(); 258 return S_OK; 259 } 260 261 HRESULT STDMETHODCALLTYPE UIDelegate::canUndo( 262 /* [retval][out] */ BOOL* result) 263 { 264 if (!result) 265 return E_POINTER; 266 267 *result = m_undoManager->canUndo(); 268 return S_OK; 269 } 270 271 HRESULT STDMETHODCALLTYPE UIDelegate::canRedo( 272 /* [retval][out] */ BOOL* result) 273 { 274 if (!result) 275 return E_POINTER; 276 277 *result = m_undoManager->canRedo(); 278 return S_OK; 279 } 280 281 HRESULT STDMETHODCALLTYPE UIDelegate::printFrame( 282 /* [in] */ IWebView *webView, 283 /* [in] */ IWebFrame *frame) 284 { 285 return E_NOTIMPL; 286 } 287 288 HRESULT STDMETHODCALLTYPE UIDelegate::ftpDirectoryTemplatePath( 289 /* [in] */ IWebView *webView, 290 /* [retval][out] */ BSTR *path) 291 { 292 if (!path) 293 return E_POINTER; 294 *path = 0; 295 return E_NOTIMPL; 296 } 297 298 299 HRESULT STDMETHODCALLTYPE UIDelegate::webViewHeaderHeight( 300 /* [in] */ IWebView *webView, 301 /* [retval][out] */ float *result) 302 { 303 if (!result) 304 return E_POINTER; 305 *result = 0; 306 return E_NOTIMPL; 307 } 308 309 HRESULT STDMETHODCALLTYPE UIDelegate::webViewFooterHeight( 310 /* [in] */ IWebView *webView, 311 /* [retval][out] */ float *result) 312 { 313 if (!result) 314 return E_POINTER; 315 *result = 0; 316 return E_NOTIMPL; 317 } 318 319 HRESULT STDMETHODCALLTYPE UIDelegate::drawHeaderInRect( 320 /* [in] */ IWebView *webView, 321 /* [in] */ RECT *rect, 322 /* [in] */ OLE_HANDLE drawingContext) 323 { 324 return E_NOTIMPL; 325 } 326 327 HRESULT STDMETHODCALLTYPE UIDelegate::drawFooterInRect( 328 /* [in] */ IWebView *webView, 329 /* [in] */ RECT *rect, 330 /* [in] */ OLE_HANDLE drawingContext, 331 /* [in] */ UINT pageIndex, 332 /* [in] */ UINT pageCount) 333 { 334 return E_NOTIMPL; 335 } 336 337 HRESULT STDMETHODCALLTYPE UIDelegate::webViewPrintingMarginRect( 338 /* [in] */ IWebView *webView, 339 /* [retval][out] */ RECT *rect) 340 { 341 return E_NOTIMPL; 342 } 343 344 HRESULT STDMETHODCALLTYPE UIDelegate::canRunModal( 345 /* [in] */ IWebView *webView, 346 /* [retval][out] */ BOOL *canRunBoolean) 347 { 348 return E_NOTIMPL; 349 } 350 351 HRESULT STDMETHODCALLTYPE UIDelegate::createModalDialog( 352 /* [in] */ IWebView *sender, 353 /* [in] */ IWebURLRequest *request, 354 /* [retval][out] */ IWebView **newWebView) 355 { 356 return E_NOTIMPL; 357 } 358 359 HRESULT STDMETHODCALLTYPE UIDelegate::runModal( 360 /* [in] */ IWebView *webView) 361 { 362 return E_NOTIMPL; 363 } 364 365 HRESULT STDMETHODCALLTYPE UIDelegate::isMenuBarVisible( 366 /* [in] */ IWebView *webView, 367 /* [retval][out] */ BOOL *visible) 368 { 369 if (!visible) 370 return E_POINTER; 371 *visible = false; 372 return E_NOTIMPL; 373 } 374 375 HRESULT STDMETHODCALLTYPE UIDelegate::setMenuBarVisible( 376 /* [in] */ IWebView *webView, 377 /* [in] */ BOOL visible) 378 { 379 return E_NOTIMPL; 380 } 381 382 HRESULT STDMETHODCALLTYPE UIDelegate::runDatabaseSizeLimitPrompt( 383 /* [in] */ IWebView *webView, 384 /* [in] */ BSTR displayName, 385 /* [in] */ IWebFrame *initiatedByFrame, 386 /* [retval][out] */ BOOL *allowed) 387 { 388 if (!allowed) 389 return E_POINTER; 390 *allowed = false; 391 return E_NOTIMPL; 392 } 393 394 HRESULT STDMETHODCALLTYPE UIDelegate::paintCustomScrollbar( 395 /* [in] */ IWebView *webView, 396 /* [in] */ HDC hDC, 397 /* [in] */ RECT rect, 398 /* [in] */ WebScrollBarControlSize size, 399 /* [in] */ WebScrollbarControlState state, 400 /* [in] */ WebScrollbarControlPart pressedPart, 401 /* [in] */ BOOL vertical, 402 /* [in] */ float value, 403 /* [in] */ float proportion, 404 /* [in] */ WebScrollbarControlPartMask parts) 405 { 406 return E_NOTIMPL; 407 } 408 409 HRESULT STDMETHODCALLTYPE UIDelegate::paintCustomScrollCorner( 410 /* [in] */ IWebView *webView, 411 /* [in] */ HDC hDC, 412 /* [in] */ RECT rect) 413 { 414 return E_NOTIMPL; 415 } 416 417 HRESULT STDMETHODCALLTYPE UIDelegate::setFrame( 418 /* [in] */ IWebView* /*sender*/, 419 /* [in] */ RECT* frame) 420 { 421 m_frame = *frame; 422 return S_OK; 423 } 424 425 HRESULT STDMETHODCALLTYPE UIDelegate::webViewFrame( 426 /* [in] */ IWebView* /*sender*/, 427 /* [retval][out] */ RECT* frame) 428 { 429 *frame = m_frame; 430 return S_OK; 431 } 432 433 HRESULT STDMETHODCALLTYPE UIDelegate::runJavaScriptAlertPanelWithMessage( 434 /* [in] */ IWebView* /*sender*/, 435 /* [in] */ BSTR message) 436 { 437 printf("ALERT: %S\n", message ? message : L""); 438 439 return S_OK; 440 } 441 442 HRESULT STDMETHODCALLTYPE UIDelegate::runJavaScriptConfirmPanelWithMessage( 443 /* [in] */ IWebView* sender, 444 /* [in] */ BSTR message, 445 /* [retval][out] */ BOOL* result) 446 { 447 printf("CONFIRM: %S\n", message ? message : L""); 448 *result = TRUE; 449 450 return S_OK; 451 } 452 453 HRESULT STDMETHODCALLTYPE UIDelegate::runJavaScriptTextInputPanelWithPrompt( 454 /* [in] */ IWebView *sender, 455 /* [in] */ BSTR message, 456 /* [in] */ BSTR defaultText, 457 /* [retval][out] */ BSTR *result) 458 { 459 printf("PROMPT: %S, default text: %S\n", message ? message : L"", defaultText ? defaultText : L""); 460 *result = SysAllocString(defaultText); 461 462 return S_OK; 463 } 464 465 HRESULT STDMETHODCALLTYPE UIDelegate::runBeforeUnloadConfirmPanelWithMessage( 466 /* [in] */ IWebView* /*sender*/, 467 /* [in] */ BSTR /*message*/, 468 /* [in] */ IWebFrame* /*initiatedByFrame*/, 469 /* [retval][out] */ BOOL* result) 470 { 471 if (!result) 472 return E_POINTER; 473 *result = TRUE; 474 return E_NOTIMPL; 475 } 476 477 HRESULT STDMETHODCALLTYPE UIDelegate::webViewAddMessageToConsole( 478 /* [in] */ IWebView* sender, 479 /* [in] */ BSTR message, 480 /* [in] */ int lineNumber, 481 /* [in] */ BSTR url, 482 /* [in] */ BOOL isError) 483 { 484 wstring newMessage; 485 if (message) { 486 newMessage = message; 487 size_t fileProtocol = newMessage.find(L"file://"); 488 if (fileProtocol != wstring::npos) 489 newMessage = newMessage.substr(0, fileProtocol) + lastPathComponent(newMessage.substr(fileProtocol)); 490 } 491 492 printf("CONSOLE MESSAGE: line %d: %s\n", lineNumber, toUTF8(newMessage).c_str()); 493 return S_OK; 494 } 495 496 HRESULT STDMETHODCALLTYPE UIDelegate::doDragDrop( 497 /* [in] */ IWebView* sender, 498 /* [in] */ IDataObject* object, 499 /* [in] */ IDropSource* source, 500 /* [in] */ DWORD okEffect, 501 /* [retval][out] */ DWORD* performedEffect) 502 { 503 if (!performedEffect) 504 return E_POINTER; 505 506 *performedEffect = 0; 507 508 draggingInfo = new DraggingInfo(object, source); 509 HRESULT oleDragAndDropReturnValue = DRAGDROP_S_CANCEL; 510 replaySavedEvents(&oleDragAndDropReturnValue); 511 if (draggingInfo) { 512 *performedEffect = draggingInfo->performedDropEffect(); 513 delete draggingInfo; 514 draggingInfo = 0; 515 } 516 return oleDragAndDropReturnValue; 517 } 518 519 HRESULT STDMETHODCALLTYPE UIDelegate::webViewGetDlgCode( 520 /* [in] */ IWebView* /*sender*/, 521 /* [in] */ UINT /*keyCode*/, 522 /* [retval][out] */ LONG_PTR *code) 523 { 524 if (!code) 525 return E_POINTER; 526 *code = 0; 527 return E_NOTIMPL; 528 } 529 530 HRESULT STDMETHODCALLTYPE UIDelegate::createWebViewWithRequest( 531 /* [in] */ IWebView *sender, 532 /* [in] */ IWebURLRequest *request, 533 /* [retval][out] */ IWebView **newWebView) 534 { 535 if (!::gLayoutTestController->canOpenWindows()) 536 return E_FAIL; 537 *newWebView = createWebViewAndOffscreenWindow(); 538 return S_OK; 539 } 540 541 HRESULT STDMETHODCALLTYPE UIDelegate::webViewClose( 542 /* [in] */ IWebView *sender) 543 { 544 HWND hostWindow; 545 sender->hostWindow(reinterpret_cast<OLE_HANDLE*>(&hostWindow)); 546 DestroyWindow(hostWindow); 547 return S_OK; 548 } 549 550 HRESULT STDMETHODCALLTYPE UIDelegate::webViewFocus( 551 /* [in] */ IWebView *sender) 552 { 553 HWND hostWindow; 554 sender->hostWindow(reinterpret_cast<OLE_HANDLE*>(&hostWindow)); 555 SetForegroundWindow(hostWindow); 556 return S_OK; 557 } 558 559 HRESULT STDMETHODCALLTYPE UIDelegate::webViewUnfocus( 560 /* [in] */ IWebView *sender) 561 { 562 SetForegroundWindow(GetDesktopWindow()); 563 return S_OK; 564 } 565 566 HRESULT STDMETHODCALLTYPE UIDelegate::webViewPainted( 567 /* [in] */ IWebView *sender) 568 { 569 return S_OK; 570 } 571 572 HRESULT STDMETHODCALLTYPE UIDelegate::exceededDatabaseQuota( 573 /* [in] */ IWebView *sender, 574 /* [in] */ IWebFrame *frame, 575 /* [in] */ IWebSecurityOrigin *origin, 576 /* [in] */ BSTR databaseIdentifier) 577 { 578 BSTR protocol; 579 BSTR host; 580 unsigned short port; 581 582 origin->protocol(&protocol); 583 origin->host(&host); 584 origin->port(&port); 585 586 if (!done && gLayoutTestController->dumpDatabaseCallbacks()) 587 printf("UI DELEGATE DATABASE CALLBACK: exceededDatabaseQuotaForSecurityOrigin:{%S, %S, %i} database:%S\n", protocol, host, port, databaseIdentifier); 588 589 SysFreeString(protocol); 590 SysFreeString(host); 591 592 static const unsigned long long defaultQuota = 5 * 1024 * 1024; 593 origin->setQuota(defaultQuota); 594 595 return S_OK; 596 } 597 598 HRESULT STDMETHODCALLTYPE UIDelegate::embeddedViewWithArguments( 599 /* [in] */ IWebView *sender, 600 /* [in] */ IWebFrame *frame, 601 /* [in] */ IPropertyBag *arguments, 602 /* [retval][out] */ IWebEmbeddedView **view) 603 { 604 if (!view) 605 return E_POINTER; 606 *view = 0; 607 return E_NOTIMPL; 608 } 609 610 HRESULT STDMETHODCALLTYPE UIDelegate::webViewClosing( 611 /* [in] */ IWebView *sender) 612 { 613 return E_NOTIMPL; 614 } 615 616 HRESULT STDMETHODCALLTYPE UIDelegate::webViewSetCursor( 617 /* [in] */ IWebView *sender, 618 /* [in] */ OLE_HANDLE cursor) 619 { 620 return E_NOTIMPL; 621 } 622 623 HRESULT STDMETHODCALLTYPE UIDelegate::webViewDidInvalidate( 624 /* [in] */ IWebView *sender) 625 { 626 return E_NOTIMPL; 627 } 628 629 HRESULT STDMETHODCALLTYPE UIDelegate::setStatusText(IWebView*, BSTR text) 630 { 631 if (gLayoutTestController->dumpStatusCallbacks()) 632 printf("UI DELEGATE STATUS CALLBACK: setStatusText:%s\n", text ? toUTF8(text).c_str() : ""); 633 return S_OK; 634 } 635 636 HRESULT STDMETHODCALLTYPE UIDelegate::desktopNotificationsDelegate(IWebDesktopNotificationsDelegate** result) 637 { 638 m_desktopNotifications.copyRefTo(result); 639 return S_OK; 640 } 641 642 HRESULT STDMETHODCALLTYPE UIDelegate::createWebViewWithRequest(IWebView* sender, IWebURLRequest* request, IPropertyBag* windowFeatures, IWebView** newWebView) 643 { 644 return E_NOTIMPL; 645 } 646 647 HRESULT STDMETHODCALLTYPE UIDelegate::drawBackground(IWebView* sender, OLE_HANDLE hdc, const RECT* dirtyRect) 648 { 649 return E_NOTIMPL; 650 } 651 652 HRESULT STDMETHODCALLTYPE UIDelegate::decidePolicyForGeolocationRequest(IWebView* sender, IWebFrame* frame, IWebSecurityOrigin* origin, IWebGeolocationPolicyListener* listener) 653 { 654 return E_NOTIMPL; 655 } 656 657 HRESULT STDMETHODCALLTYPE UIDelegate::didPressMissingPluginButton(IDOMElement* element) 658 { 659 printf("MISSING PLUGIN BUTTON PRESSED\n"); 660 return S_OK; 661 } 662 663