/* * Copyright (C) 2005, 2006, 2007, 2008 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of * its contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "config.h" #include "UIDelegate.h" #include "DumpRenderTree.h" #include "DraggingInfo.h" #include "EventSender.h" #include "LayoutTestController.h" #include "DRTDesktopNotificationPresenter.h" #include #include #include #include #include #include #include using std::wstring; class DRTUndoObject { public: DRTUndoObject(IWebUndoTarget* target, BSTR actionName, IUnknown* obj) : m_target(target) , m_actionName(SysAllocString(actionName)) , m_obj(obj) { } ~DRTUndoObject() { SysFreeString(m_actionName); } void invoke() { m_target->invoke(m_actionName, m_obj.get()); } private: IWebUndoTarget* m_target; BSTR m_actionName; COMPtr m_obj; }; class DRTUndoStack { public: ~DRTUndoStack() { deleteAllValues(m_undoVector); } bool isEmpty() const { return m_undoVector.isEmpty(); } void clear() { deleteAllValues(m_undoVector); m_undoVector.clear(); } void push(DRTUndoObject* undoObject) { m_undoVector.append(undoObject); } DRTUndoObject* pop() { DRTUndoObject* top = m_undoVector.last(); m_undoVector.removeLast(); return top; } private: Vector m_undoVector; }; class DRTUndoManager { public: DRTUndoManager(); void removeAllActions(); void registerUndoWithTarget(IWebUndoTarget* target, BSTR actionName, IUnknown* obj); void redo(); void undo(); bool canRedo() { return !m_redoStack->isEmpty(); } bool canUndo() { return !m_undoStack->isEmpty(); } private: OwnPtr m_redoStack; OwnPtr m_undoStack; bool m_isRedoing; bool m_isUndoing; }; DRTUndoManager::DRTUndoManager() : m_redoStack(new DRTUndoStack) , m_undoStack(new DRTUndoStack) , m_isRedoing(false) , m_isUndoing(false) { } void DRTUndoManager::removeAllActions() { m_redoStack->clear(); m_undoStack->clear(); } void DRTUndoManager::registerUndoWithTarget(IWebUndoTarget* target, BSTR actionName, IUnknown* obj) { if (!m_isUndoing && !m_isRedoing) m_redoStack->clear(); DRTUndoStack* stack = m_isUndoing ? m_redoStack.get() : m_undoStack.get(); stack->push(new DRTUndoObject(target, actionName, obj)); } void DRTUndoManager::redo() { if (!canRedo()) return; m_isRedoing = true; DRTUndoObject* redoObject = m_redoStack->pop(); redoObject->invoke(); delete redoObject; m_isRedoing = false; } void DRTUndoManager::undo() { if (!canUndo()) return; m_isUndoing = true; DRTUndoObject* undoObject = m_undoStack->pop(); undoObject->invoke(); delete undoObject; m_isUndoing = false; } UIDelegate::UIDelegate() : m_refCount(1) , m_undoManager(new DRTUndoManager) , m_desktopNotifications(new DRTDesktopNotificationPresenter) { m_frame.bottom = 0; m_frame.top = 0; m_frame.left = 0; m_frame.right = 0; } void UIDelegate::resetUndoManager() { m_undoManager.set(new DRTUndoManager); } HRESULT STDMETHODCALLTYPE UIDelegate::QueryInterface(REFIID riid, void** ppvObject) { *ppvObject = 0; if (IsEqualGUID(riid, IID_IUnknown)) *ppvObject = static_cast(this); else if (IsEqualGUID(riid, IID_IWebUIDelegate)) *ppvObject = static_cast(this); else if (IsEqualGUID(riid, IID_IWebUIDelegate2)) *ppvObject = static_cast(this); else if (IsEqualGUID(riid, IID_IWebUIDelegatePrivate)) *ppvObject = static_cast(this); else return E_NOINTERFACE; AddRef(); return S_OK; } ULONG STDMETHODCALLTYPE UIDelegate::AddRef() { return ++m_refCount; } ULONG STDMETHODCALLTYPE UIDelegate::Release() { ULONG newRef = --m_refCount; if (!newRef) delete(this); return newRef; } HRESULT STDMETHODCALLTYPE UIDelegate::hasCustomMenuImplementation( /* [retval][out] */ BOOL *hasCustomMenus) { *hasCustomMenus = TRUE; return S_OK; } HRESULT STDMETHODCALLTYPE UIDelegate::trackCustomPopupMenu( /* [in] */ IWebView *sender, /* [in] */ OLE_HANDLE menu, /* [in] */ LPPOINT point) { // Do nothing return S_OK; } HRESULT STDMETHODCALLTYPE UIDelegate::registerUndoWithTarget( /* [in] */ IWebUndoTarget* target, /* [in] */ BSTR actionName, /* [in] */ IUnknown* actionArg) { m_undoManager->registerUndoWithTarget(target, actionName, actionArg); return S_OK; } HRESULT STDMETHODCALLTYPE UIDelegate::removeAllActionsWithTarget( /* [in] */ IWebUndoTarget*) { m_undoManager->removeAllActions(); return S_OK; } HRESULT STDMETHODCALLTYPE UIDelegate::setActionTitle( /* [in] */ BSTR actionTitle) { // It is not neccessary to implement this for DRT because there is // menu to write out the title to. return S_OK; } HRESULT STDMETHODCALLTYPE UIDelegate::undo() { m_undoManager->undo(); return S_OK; } HRESULT STDMETHODCALLTYPE UIDelegate::redo() { m_undoManager->redo(); return S_OK; } HRESULT STDMETHODCALLTYPE UIDelegate::canUndo( /* [retval][out] */ BOOL* result) { if (!result) return E_POINTER; *result = m_undoManager->canUndo(); return S_OK; } HRESULT STDMETHODCALLTYPE UIDelegate::canRedo( /* [retval][out] */ BOOL* result) { if (!result) return E_POINTER; *result = m_undoManager->canRedo(); return S_OK; } HRESULT STDMETHODCALLTYPE UIDelegate::printFrame( /* [in] */ IWebView *webView, /* [in] */ IWebFrame *frame) { return E_NOTIMPL; } HRESULT STDMETHODCALLTYPE UIDelegate::ftpDirectoryTemplatePath( /* [in] */ IWebView *webView, /* [retval][out] */ BSTR *path) { if (!path) return E_POINTER; *path = 0; return E_NOTIMPL; } HRESULT STDMETHODCALLTYPE UIDelegate::webViewHeaderHeight( /* [in] */ IWebView *webView, /* [retval][out] */ float *result) { if (!result) return E_POINTER; *result = 0; return E_NOTIMPL; } HRESULT STDMETHODCALLTYPE UIDelegate::webViewFooterHeight( /* [in] */ IWebView *webView, /* [retval][out] */ float *result) { if (!result) return E_POINTER; *result = 0; return E_NOTIMPL; } HRESULT STDMETHODCALLTYPE UIDelegate::drawHeaderInRect( /* [in] */ IWebView *webView, /* [in] */ RECT *rect, /* [in] */ OLE_HANDLE drawingContext) { return E_NOTIMPL; } HRESULT STDMETHODCALLTYPE UIDelegate::drawFooterInRect( /* [in] */ IWebView *webView, /* [in] */ RECT *rect, /* [in] */ OLE_HANDLE drawingContext, /* [in] */ UINT pageIndex, /* [in] */ UINT pageCount) { return E_NOTIMPL; } HRESULT STDMETHODCALLTYPE UIDelegate::webViewPrintingMarginRect( /* [in] */ IWebView *webView, /* [retval][out] */ RECT *rect) { return E_NOTIMPL; } HRESULT STDMETHODCALLTYPE UIDelegate::canRunModal( /* [in] */ IWebView *webView, /* [retval][out] */ BOOL *canRunBoolean) { return E_NOTIMPL; } HRESULT STDMETHODCALLTYPE UIDelegate::createModalDialog( /* [in] */ IWebView *sender, /* [in] */ IWebURLRequest *request, /* [retval][out] */ IWebView **newWebView) { return E_NOTIMPL; } HRESULT STDMETHODCALLTYPE UIDelegate::runModal( /* [in] */ IWebView *webView) { return E_NOTIMPL; } HRESULT STDMETHODCALLTYPE UIDelegate::isMenuBarVisible( /* [in] */ IWebView *webView, /* [retval][out] */ BOOL *visible) { if (!visible) return E_POINTER; *visible = false; return E_NOTIMPL; } HRESULT STDMETHODCALLTYPE UIDelegate::setMenuBarVisible( /* [in] */ IWebView *webView, /* [in] */ BOOL visible) { return E_NOTIMPL; } HRESULT STDMETHODCALLTYPE UIDelegate::runDatabaseSizeLimitPrompt( /* [in] */ IWebView *webView, /* [in] */ BSTR displayName, /* [in] */ IWebFrame *initiatedByFrame, /* [retval][out] */ BOOL *allowed) { if (!allowed) return E_POINTER; *allowed = false; return E_NOTIMPL; } HRESULT STDMETHODCALLTYPE UIDelegate::paintCustomScrollbar( /* [in] */ IWebView *webView, /* [in] */ HDC hDC, /* [in] */ RECT rect, /* [in] */ WebScrollBarControlSize size, /* [in] */ WebScrollbarControlState state, /* [in] */ WebScrollbarControlPart pressedPart, /* [in] */ BOOL vertical, /* [in] */ float value, /* [in] */ float proportion, /* [in] */ WebScrollbarControlPartMask parts) { return E_NOTIMPL; } HRESULT STDMETHODCALLTYPE UIDelegate::paintCustomScrollCorner( /* [in] */ IWebView *webView, /* [in] */ HDC hDC, /* [in] */ RECT rect) { return E_NOTIMPL; } HRESULT STDMETHODCALLTYPE UIDelegate::setFrame( /* [in] */ IWebView* /*sender*/, /* [in] */ RECT* frame) { m_frame = *frame; return S_OK; } HRESULT STDMETHODCALLTYPE UIDelegate::webViewFrame( /* [in] */ IWebView* /*sender*/, /* [retval][out] */ RECT* frame) { *frame = m_frame; return S_OK; } HRESULT STDMETHODCALLTYPE UIDelegate::runJavaScriptAlertPanelWithMessage( /* [in] */ IWebView* /*sender*/, /* [in] */ BSTR message) { printf("ALERT: %S\n", message ? message : L""); return S_OK; } HRESULT STDMETHODCALLTYPE UIDelegate::runJavaScriptConfirmPanelWithMessage( /* [in] */ IWebView* sender, /* [in] */ BSTR message, /* [retval][out] */ BOOL* result) { printf("CONFIRM: %S\n", message ? message : L""); *result = TRUE; return S_OK; } HRESULT STDMETHODCALLTYPE UIDelegate::runJavaScriptTextInputPanelWithPrompt( /* [in] */ IWebView *sender, /* [in] */ BSTR message, /* [in] */ BSTR defaultText, /* [retval][out] */ BSTR *result) { printf("PROMPT: %S, default text: %S\n", message ? message : L"", defaultText ? defaultText : L""); *result = SysAllocString(defaultText); return S_OK; } HRESULT STDMETHODCALLTYPE UIDelegate::runBeforeUnloadConfirmPanelWithMessage( /* [in] */ IWebView* /*sender*/, /* [in] */ BSTR /*message*/, /* [in] */ IWebFrame* /*initiatedByFrame*/, /* [retval][out] */ BOOL* result) { if (!result) return E_POINTER; *result = TRUE; return E_NOTIMPL; } HRESULT STDMETHODCALLTYPE UIDelegate::webViewAddMessageToConsole( /* [in] */ IWebView* sender, /* [in] */ BSTR message, /* [in] */ int lineNumber, /* [in] */ BSTR url, /* [in] */ BOOL isError) { wstring newMessage; if (message) { newMessage = message; size_t fileProtocol = newMessage.find(L"file://"); if (fileProtocol != wstring::npos) newMessage = newMessage.substr(0, fileProtocol) + urlSuitableForTestResult(newMessage.substr(fileProtocol)); } printf("CONSOLE MESSAGE: line %d: %S\n", lineNumber, newMessage.c_str()); return S_OK; } HRESULT STDMETHODCALLTYPE UIDelegate::doDragDrop( /* [in] */ IWebView* sender, /* [in] */ IDataObject* object, /* [in] */ IDropSource* source, /* [in] */ DWORD okEffect, /* [retval][out] */ DWORD* performedEffect) { if (!performedEffect) return E_POINTER; *performedEffect = 0; draggingInfo = new DraggingInfo(object, source); HRESULT oleDragAndDropReturnValue = DRAGDROP_S_CANCEL; replaySavedEvents(&oleDragAndDropReturnValue); if (draggingInfo) { *performedEffect = draggingInfo->performedDropEffect(); delete draggingInfo; draggingInfo = 0; } return oleDragAndDropReturnValue; } HRESULT STDMETHODCALLTYPE UIDelegate::webViewGetDlgCode( /* [in] */ IWebView* /*sender*/, /* [in] */ UINT /*keyCode*/, /* [retval][out] */ LONG_PTR *code) { if (!code) return E_POINTER; *code = 0; return E_NOTIMPL; } HRESULT STDMETHODCALLTYPE UIDelegate::createWebViewWithRequest( /* [in] */ IWebView *sender, /* [in] */ IWebURLRequest *request, /* [retval][out] */ IWebView **newWebView) { if (!::gLayoutTestController->canOpenWindows()) return E_FAIL; *newWebView = createWebViewAndOffscreenWindow(); return S_OK; } HRESULT STDMETHODCALLTYPE UIDelegate::webViewClose( /* [in] */ IWebView *sender) { HWND hostWindow; sender->hostWindow(reinterpret_cast(&hostWindow)); DestroyWindow(hostWindow); return S_OK; } HRESULT STDMETHODCALLTYPE UIDelegate::webViewFocus( /* [in] */ IWebView *sender) { HWND hostWindow; sender->hostWindow(reinterpret_cast(&hostWindow)); SetForegroundWindow(hostWindow); return S_OK; } HRESULT STDMETHODCALLTYPE UIDelegate::webViewUnfocus( /* [in] */ IWebView *sender) { SetForegroundWindow(GetDesktopWindow()); return S_OK; } HRESULT STDMETHODCALLTYPE UIDelegate::webViewPainted( /* [in] */ IWebView *sender) { return S_OK; } HRESULT STDMETHODCALLTYPE UIDelegate::exceededDatabaseQuota( /* [in] */ IWebView *sender, /* [in] */ IWebFrame *frame, /* [in] */ IWebSecurityOrigin *origin, /* [in] */ BSTR databaseIdentifier) { BSTR protocol; BSTR host; unsigned short port; origin->protocol(&protocol); origin->host(&host); origin->port(&port); if (!done && gLayoutTestController->dumpDatabaseCallbacks()) printf("UI DELEGATE DATABASE CALLBACK: exceededDatabaseQuotaForSecurityOrigin:{%S, %S, %i} database:%S\n", protocol, host, port, databaseIdentifier); SysFreeString(protocol); SysFreeString(host); static const unsigned long long defaultQuota = 5 * 1024 * 1024; origin->setQuota(defaultQuota); return S_OK; } HRESULT STDMETHODCALLTYPE UIDelegate::embeddedViewWithArguments( /* [in] */ IWebView *sender, /* [in] */ IWebFrame *frame, /* [in] */ IPropertyBag *arguments, /* [retval][out] */ IWebEmbeddedView **view) { if (!view) return E_POINTER; *view = 0; return E_NOTIMPL; } HRESULT STDMETHODCALLTYPE UIDelegate::webViewClosing( /* [in] */ IWebView *sender) { return E_NOTIMPL; } HRESULT STDMETHODCALLTYPE UIDelegate::webViewSetCursor( /* [in] */ IWebView *sender, /* [in] */ OLE_HANDLE cursor) { return E_NOTIMPL; } HRESULT STDMETHODCALLTYPE UIDelegate::webViewDidInvalidate( /* [in] */ IWebView *sender) { return E_NOTIMPL; } HRESULT STDMETHODCALLTYPE UIDelegate::setStatusText(IWebView*, BSTR text) { if (gLayoutTestController->dumpStatusCallbacks()) printf("UI DELEGATE STATUS CALLBACK: setStatusText:%S\n", text ? text : L""); return S_OK; } HRESULT STDMETHODCALLTYPE UIDelegate::desktopNotificationsDelegate(IWebDesktopNotificationsDelegate** result) { m_desktopNotifications.copyRefTo(result); return S_OK; }