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 <shlobj.h> 33 34 #include <WebCore/ClipboardWin.h> 35 #include <WebCore/DragController.h> 36 #include <WebCore/DragData.h> 37 #include <WebCore/FrameView.h> 38 #include <WebCore/GraphicsContext.h> 39 #include <WebCore/Page.h> 40 41 using namespace WebCore; 42 43 static DWORD draggingSourceOperationMaskToDragCursors(DragOperation op) 44 { 45 DWORD result = DROPEFFECT_NONE; 46 if (op == DragOperationEvery) 47 return DROPEFFECT_COPY | DROPEFFECT_LINK | DROPEFFECT_MOVE; 48 if (op & DragOperationCopy) 49 result |= DROPEFFECT_COPY; 50 if (op & DragOperationLink) 51 result |= DROPEFFECT_LINK; 52 if (op & DragOperationMove) 53 result |= DROPEFFECT_MOVE; 54 if (op & DragOperationGeneric) 55 result |= DROPEFFECT_MOVE; 56 return result; 57 } 58 59 WebDragClient::WebDragClient(WebView* webView) 60 : m_webView(webView) 61 { 62 ASSERT(webView); 63 } 64 65 DragDestinationAction WebDragClient::actionMaskForDrag(DragData* dragData) 66 { 67 COMPtr<IWebUIDelegate> delegateRef = 0; 68 //Default behaviour (eg. no delegate, or callback not implemented) is to allow 69 //any action 70 WebDragDestinationAction mask = WebDragDestinationActionAny; 71 if (SUCCEEDED(m_webView->uiDelegate(&delegateRef))) 72 delegateRef->dragDestinationActionMaskForDraggingInfo(m_webView, dragData->platformData(), &mask); 73 74 return (DragDestinationAction)mask; 75 } 76 77 void WebDragClient::willPerformDragDestinationAction(DragDestinationAction action, DragData* dragData) 78 { 79 //Default delegate for willPerformDragDestinationAction has no side effects 80 //so we just call the delegate, and don't worry about whether it's implemented 81 COMPtr<IWebUIDelegate> delegateRef = 0; 82 if (SUCCEEDED(m_webView->uiDelegate(&delegateRef))) 83 delegateRef->willPerformDragDestinationAction(m_webView, (WebDragDestinationAction)action, dragData->platformData()); 84 } 85 86 DragSourceAction WebDragClient::dragSourceActionMaskForPoint(const IntPoint& windowPoint) 87 { 88 COMPtr<IWebUIDelegate> delegateRef = 0; 89 WebDragSourceAction action = WebDragSourceActionAny; 90 POINT localpt = core(m_webView)->mainFrame()->view()->windowToContents(windowPoint); 91 if (SUCCEEDED(m_webView->uiDelegate(&delegateRef))) 92 delegateRef->dragSourceActionMaskForPoint(m_webView, &localpt, &action); 93 return (DragSourceAction)action; 94 } 95 96 void WebDragClient::willPerformDragSourceAction(DragSourceAction action, const IntPoint& intPoint, Clipboard* clipboard) 97 { 98 COMPtr<IWebUIDelegate> uiDelegate; 99 if (!SUCCEEDED(m_webView->uiDelegate(&uiDelegate))) 100 return; 101 102 POINT point = intPoint; 103 COMPtr<IDataObject> dataObject = static_cast<ClipboardWin*>(clipboard)->dataObject(); 104 105 COMPtr<IDataObject> newDataObject; 106 HRESULT result = uiDelegate->willPerformDragSourceAction(m_webView, static_cast<WebDragSourceAction>(action), &point, dataObject.get(), &newDataObject); 107 if (result == S_OK && newDataObject != dataObject) 108 static_cast<ClipboardWin*>(clipboard)->setExternalDataObject(newDataObject.get()); 109 } 110 111 void WebDragClient::startDrag(DragImageRef image, const IntPoint& imageOrigin, const IntPoint& dragPoint, Clipboard* clipboard, Frame* frame, bool isLink) 112 { 113 //FIXME: Allow UIDelegate to override behaviour <rdar://problem/5015953> 114 115 //We liberally protect everything, to protect against a load occurring mid-drag 116 RefPtr<Frame> frameProtector = frame; 117 COMPtr<IDragSourceHelper> helper; 118 COMPtr<IDataObject> dataObject; 119 COMPtr<WebView> viewProtector = m_webView; 120 COMPtr<IDropSource> source; 121 if (FAILED(WebDropSource::createInstance(m_webView, &source))) 122 return; 123 124 dataObject = static_cast<ClipboardWin*>(clipboard)->dataObject(); 125 if (source && (image || dataObject)) { 126 if (image) { 127 if(SUCCEEDED(CoCreateInstance(CLSID_DragDropHelper, 0, CLSCTX_INPROC_SERVER, 128 IID_IDragSourceHelper,(LPVOID*)&helper))) { 129 BITMAP b; 130 GetObject(image, sizeof(BITMAP), &b); 131 SHDRAGIMAGE sdi; 132 sdi.sizeDragImage.cx = b.bmWidth; 133 sdi.sizeDragImage.cy = b.bmHeight; 134 sdi.crColorKey = 0xffffffff; 135 sdi.hbmpDragImage = image; 136 sdi.ptOffset.x = dragPoint.x() - imageOrigin.x(); 137 sdi.ptOffset.y = dragPoint.y() - imageOrigin.y(); 138 if (isLink) 139 sdi.ptOffset.y = b.bmHeight - sdi.ptOffset.y; 140 141 helper->InitializeFromBitmap(&sdi, dataObject.get()); 142 } 143 } 144 145 DWORD okEffect = draggingSourceOperationMaskToDragCursors(m_webView->page()->dragController()->sourceDragOperation()); 146 DWORD effect = DROPEFFECT_NONE; 147 COMPtr<IWebUIDelegate> ui; 148 HRESULT hr = E_NOTIMPL; 149 if (SUCCEEDED(m_webView->uiDelegate(&ui))) { 150 COMPtr<IWebUIDelegatePrivate> uiPrivate; 151 if (SUCCEEDED(ui->QueryInterface(IID_IWebUIDelegatePrivate, (void**)&uiPrivate))) 152 hr = uiPrivate->doDragDrop(m_webView, dataObject.get(), source.get(), okEffect, &effect); 153 } 154 if (hr == E_NOTIMPL) 155 hr = DoDragDrop(dataObject.get(), source.get(), okEffect, &effect); 156 157 DragOperation operation = DragOperationNone; 158 if (hr == DRAGDROP_S_DROP) { 159 if (effect & DROPEFFECT_COPY) 160 operation = DragOperationCopy; 161 else if (effect & DROPEFFECT_LINK) 162 operation = DragOperationLink; 163 else if (effect & DROPEFFECT_MOVE) 164 operation = DragOperationMove; 165 } 166 frame->eventHandler()->dragSourceEndedAt(generateMouseEvent(m_webView, false), operation); 167 } 168 } 169 170 void WebDragClient::dragControllerDestroyed() 171 { 172 delete this; 173 } 174