1/* 2 * Copyright (C) 2007 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 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY 14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR 17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 */ 25 26#include "config.h" 27#include "WebDragClient.h" 28#include "WebDropSource.h" 29#include "WebKitGraphics.h" 30#include "WebView.h" 31 32#include <WebCore/Clipboard.h> 33#include <WebCore/DragController.h> 34#include <WebCore/DragData.h> 35#include <WebCore/EventHandler.h> 36#include <WebCore/Page.h> 37#include <WebCore/Pasteboard.h> 38#include <WebCore/PlatformMouseEvent.h> 39#include <WebCore/Frame.h> 40#include <WebCore/FrameView.h> 41#include <WebCore/GraphicsContext.h> 42#include <shlobj.h> 43 44using namespace WebCore; 45 46static DWORD draggingSourceOperationMaskToDragCursors(DragOperation op) 47{ 48 DWORD result = DROPEFFECT_NONE; 49 if (op == DragOperationEvery) 50 return DROPEFFECT_COPY | DROPEFFECT_LINK | DROPEFFECT_MOVE; 51 if (op & DragOperationCopy) 52 result |= DROPEFFECT_COPY; 53 if (op & DragOperationLink) 54 result |= DROPEFFECT_LINK; 55 if (op & DragOperationMove) 56 result |= DROPEFFECT_MOVE; 57 if (op & DragOperationGeneric) 58 result |= DROPEFFECT_MOVE; 59 return result; 60} 61 62WebDragClient::WebDragClient(WebView* webView) 63 : m_webView(webView) 64{ 65 ASSERT(webView); 66} 67 68DragDestinationAction WebDragClient::actionMaskForDrag(DragData* dragData) 69{ 70 COMPtr<IWebUIDelegate> delegateRef = 0; 71 //Default behaviour (eg. no delegate, or callback not implemented) is to allow 72 //any action 73 WebDragDestinationAction mask = WebDragDestinationActionAny; 74 if (SUCCEEDED(m_webView->uiDelegate(&delegateRef))) 75 delegateRef->dragDestinationActionMaskForDraggingInfo(m_webView, dragData->platformData(), &mask); 76 77 return (DragDestinationAction)mask; 78} 79 80void WebDragClient::willPerformDragDestinationAction(DragDestinationAction action, DragData* dragData) 81{ 82 //Default delegate for willPerformDragDestinationAction has no side effects 83 //so we just call the delegate, and don't worry about whether it's implemented 84 COMPtr<IWebUIDelegate> delegateRef = 0; 85 if (SUCCEEDED(m_webView->uiDelegate(&delegateRef))) 86 delegateRef->willPerformDragDestinationAction(m_webView, (WebDragDestinationAction)action, dragData->platformData()); 87} 88 89DragSourceAction WebDragClient::dragSourceActionMaskForPoint(const IntPoint& windowPoint) 90{ 91 COMPtr<IWebUIDelegate> delegateRef = 0; 92 WebDragSourceAction action = WebDragSourceActionAny; 93 POINT localpt = core(m_webView)->mainFrame()->view()->windowToContents(windowPoint); 94 if (SUCCEEDED(m_webView->uiDelegate(&delegateRef))) 95 delegateRef->dragSourceActionMaskForPoint(m_webView, &localpt, &action); 96 return (DragSourceAction)action; 97} 98 99void WebDragClient::willPerformDragSourceAction(DragSourceAction action, const IntPoint& intPoint, Clipboard* clipboard) 100{ 101 COMPtr<IWebUIDelegate> uiDelegate; 102 if (!SUCCEEDED(m_webView->uiDelegate(&uiDelegate))) 103 return; 104 105 POINT point = intPoint; 106 COMPtr<IDataObject> dataObject = clipboard->pasteboard().dataObject(); 107 108 COMPtr<IDataObject> newDataObject; 109 HRESULT result = uiDelegate->willPerformDragSourceAction(m_webView, static_cast<WebDragSourceAction>(action), &point, dataObject.get(), &newDataObject); 110 if (result == S_OK && newDataObject != dataObject) 111 const_cast<Pasteboard&>(clipboard->pasteboard()).setExternalDataObject(newDataObject.get()); 112} 113 114void WebDragClient::startDrag(DragImageRef image, const IntPoint& imageOrigin, const IntPoint& dragPoint, Clipboard* clipboard, Frame* frame, bool isLink) 115{ 116 //FIXME: Allow UIDelegate to override behaviour <rdar://problem/5015953> 117 118 //We liberally protect everything, to protect against a load occurring mid-drag 119 RefPtr<Frame> frameProtector = frame; 120 COMPtr<IDragSourceHelper> helper; 121 COMPtr<IDataObject> dataObject; 122 COMPtr<WebView> viewProtector = m_webView; 123 COMPtr<IDropSource> source; 124 if (FAILED(WebDropSource::createInstance(m_webView, &source))) 125 return; 126 127 dataObject = clipboard->pasteboard().dataObject(); 128 if (source && (image || dataObject)) { 129 if (image) { 130 if(SUCCEEDED(CoCreateInstance(CLSID_DragDropHelper, 0, CLSCTX_INPROC_SERVER, 131 IID_IDragSourceHelper,(LPVOID*)&helper))) { 132 BITMAP b; 133 GetObject(image, sizeof(BITMAP), &b); 134 SHDRAGIMAGE sdi; 135 sdi.sizeDragImage.cx = b.bmWidth; 136 sdi.sizeDragImage.cy = b.bmHeight; 137 sdi.crColorKey = 0xffffffff; 138 sdi.hbmpDragImage = image; 139 sdi.ptOffset.x = dragPoint.x() - imageOrigin.x(); 140 sdi.ptOffset.y = dragPoint.y() - imageOrigin.y(); 141 if (isLink) 142 sdi.ptOffset.y = b.bmHeight - sdi.ptOffset.y; 143 144 helper->InitializeFromBitmap(&sdi, dataObject.get()); 145 } 146 } 147 148 DWORD okEffect = draggingSourceOperationMaskToDragCursors(m_webView->page()->dragController()->sourceDragOperation()); 149 DWORD effect = DROPEFFECT_NONE; 150 COMPtr<IWebUIDelegate> ui; 151 HRESULT hr = E_NOTIMPL; 152 if (SUCCEEDED(m_webView->uiDelegate(&ui))) { 153 COMPtr<IWebUIDelegatePrivate> uiPrivate; 154 if (SUCCEEDED(ui->QueryInterface(IID_IWebUIDelegatePrivate, (void**)&uiPrivate))) 155 hr = uiPrivate->doDragDrop(m_webView, dataObject.get(), source.get(), okEffect, &effect); 156 } 157 if (hr == E_NOTIMPL) 158 hr = DoDragDrop(dataObject.get(), source.get(), okEffect, &effect); 159 160 DragOperation operation = DragOperationNone; 161 if (hr == DRAGDROP_S_DROP) { 162 if (effect & DROPEFFECT_COPY) 163 operation = DragOperationCopy; 164 else if (effect & DROPEFFECT_LINK) 165 operation = DragOperationLink; 166 else if (effect & DROPEFFECT_MOVE) 167 operation = DragOperationMove; 168 } 169 frame->eventHandler()->dragSourceEndedAt(generateMouseEvent(m_webView, false), operation); 170 } 171} 172 173void WebDragClient::dragControllerDestroyed() 174{ 175 delete this; 176} 177