|
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 #include <CoreGraphics/CoreGraphics.h> |
|
34 |
|
35 #pragma warning(push, 0) |
|
36 #include <WebCore/ClipboardWin.h> |
|
37 #include <WebCore/DragData.h> |
|
38 #include <WebCore/Font.h> |
|
39 #include <WebCore/FontDescription.h> |
|
40 #include <WebCore/FrameView.h> |
|
41 #include <WebCore/GraphicsContext.h> |
|
42 #include <WebCore/Page.h> |
|
43 #include <WebCore/StringTruncator.h> |
|
44 #include <WebCore/WebCoreTextRenderer.h> |
|
45 #pragma warning(pop) |
|
46 |
|
47 namespace WebCore { |
|
48 HBITMAP allocImage(HDC dc, IntSize size, CGContextRef *targetRef); |
|
49 } |
|
50 |
|
51 |
|
52 #define DRAG_LABEL_BORDER_X 4 |
|
53 // Keep border_y in synch with DragController::LinkDragBorderInset |
|
54 #define DRAG_LABEL_BORDER_Y 2 |
|
55 #define DRAG_LABEL_RADIUS 5 |
|
56 #define DRAG_LABEL_BORDER_Y_OFFSET 2 |
|
57 |
|
58 #define MIN_DRAG_LABEL_WIDTH_BEFORE_CLIP 120 |
|
59 |
|
60 // Observation says max size is 200x200 |
|
61 #define MAX_DRAG_LABEL_WIDTH 200 |
|
62 #define MAX_DRAG_LABEL_STRING_WIDTH (MAX_DRAG_LABEL_WIDTH - 2 * DRAG_LABEL_BORDER_X) |
|
63 |
|
64 #define DRAG_LINK_LABEL_FONT_SIZE 11 |
|
65 #define DRAG_LINK_URL_FONT_SIZE 10 |
|
66 |
|
67 using namespace WebCore; |
|
68 |
|
69 WebDragClient::WebDragClient(WebView* webView) |
|
70 : m_webView(webView) |
|
71 { |
|
72 ASSERT(webView); |
|
73 } |
|
74 |
|
75 DragDestinationAction WebDragClient::actionMaskForDrag(DragData* dragData) |
|
76 { |
|
77 COMPtr<IWebUIDelegate> delegateRef = 0; |
|
78 //Default behaviour (eg. no delegate, or callback not implemented) is to allow |
|
79 //any action |
|
80 WebDragDestinationAction mask = WebDragDestinationActionAny; |
|
81 if (SUCCEEDED(m_webView->uiDelegate(&delegateRef))) |
|
82 delegateRef->dragDestinationActionMaskForDraggingInfo(m_webView, dragData->platformData(), &mask); |
|
83 |
|
84 return (DragDestinationAction)mask; |
|
85 } |
|
86 |
|
87 void WebDragClient::willPerformDragDestinationAction(DragDestinationAction action, DragData* dragData) |
|
88 { |
|
89 //Default delegate for willPerformDragDestinationAction has no side effects |
|
90 //so we just call the delegate, and don't worry about whether it's implemented |
|
91 COMPtr<IWebUIDelegate> delegateRef = 0; |
|
92 if (SUCCEEDED(m_webView->uiDelegate(&delegateRef))) |
|
93 delegateRef->willPerformDragDestinationAction(m_webView, (WebDragDestinationAction)action, dragData->platformData()); |
|
94 } |
|
95 |
|
96 DragSourceAction WebDragClient::dragSourceActionMaskForPoint(const IntPoint& windowPoint) |
|
97 { |
|
98 COMPtr<IWebUIDelegate> delegateRef = 0; |
|
99 WebDragSourceAction action = WebDragSourceActionAny; |
|
100 POINT localpt = core(m_webView)->mainFrame()->view()->windowToContents(windowPoint); |
|
101 if (SUCCEEDED(m_webView->uiDelegate(&delegateRef))) |
|
102 delegateRef->dragSourceActionMaskForPoint(m_webView, &localpt, &action); |
|
103 return (DragSourceAction)action; |
|
104 } |
|
105 |
|
106 void WebDragClient::willPerformDragSourceAction(DragSourceAction, const IntPoint&, Clipboard*) |
|
107 { |
|
108 } |
|
109 |
|
110 void WebDragClient::startDrag(DragImageRef image, const IntPoint& imageOrigin, const IntPoint& dragPoint, Clipboard* clipboard, Frame* frame, bool isLink) |
|
111 { |
|
112 //FIXME: Allow UIDelegate to override behaviour <rdar://problem/5015953> |
|
113 |
|
114 //We liberally protect everything, to protect against a load occurring mid-drag |
|
115 RefPtr<Frame> frameProtector = frame; |
|
116 COMPtr<IDragSourceHelper> helper; |
|
117 COMPtr<IDataObject> dataObject; |
|
118 COMPtr<WebView> viewProtector = m_webView; |
|
119 COMPtr<IDropSource> source; |
|
120 if (FAILED(WebDropSource::createInstance(m_webView, &source))) |
|
121 return; |
|
122 |
|
123 dataObject = static_cast<ClipboardWin*>(clipboard)->dataObject(); |
|
124 if (source && (image || dataObject)) { |
|
125 if (image) { |
|
126 if(SUCCEEDED(CoCreateInstance(CLSID_DragDropHelper, 0, CLSCTX_INPROC_SERVER, |
|
127 IID_IDragSourceHelper,(LPVOID*)&helper))) { |
|
128 BITMAP b; |
|
129 GetObject(image, sizeof(BITMAP), &b); |
|
130 SHDRAGIMAGE sdi; |
|
131 sdi.sizeDragImage.cx = b.bmWidth; |
|
132 sdi.sizeDragImage.cy = b.bmHeight; |
|
133 sdi.crColorKey = 0xffffffff; |
|
134 sdi.hbmpDragImage = image; |
|
135 sdi.ptOffset.x = dragPoint.x() - imageOrigin.x(); |
|
136 sdi.ptOffset.y = dragPoint.y() - imageOrigin.y(); |
|
137 if (isLink) |
|
138 sdi.ptOffset.y = b.bmHeight - sdi.ptOffset.y; |
|
139 |
|
140 helper->InitializeFromBitmap(&sdi, dataObject.get()); |
|
141 } |
|
142 } |
|
143 |
|
144 //FIXME: Ensure correct drag ops are available <rdar://problem/5015957> |
|
145 DWORD okEffect = DROPEFFECT_COPY | DROPEFFECT_LINK | DROPEFFECT_MOVE; |
|
146 DWORD effect; |
|
147 COMPtr<IWebUIDelegate> ui; |
|
148 if (SUCCEEDED(m_webView->uiDelegate(&ui))) { |
|
149 COMPtr<IWebUIDelegatePrivate> uiPrivate; |
|
150 if (SUCCEEDED(ui->QueryInterface(IID_IWebUIDelegatePrivate, (void**)&uiPrivate))) |
|
151 if (SUCCEEDED(uiPrivate->doDragDrop(m_webView, dataObject.get(), source.get(), okEffect, &effect))) |
|
152 return; |
|
153 } |
|
154 |
|
155 DoDragDrop(dataObject.get(), source.get(), okEffect, &effect); |
|
156 } |
|
157 } |
|
158 |
|
159 static Font dragLabelFont(int size, bool bold) |
|
160 { |
|
161 FontDescription desc; |
|
162 desc.setBold(bold); |
|
163 FontFamily family; |
|
164 family.setFamily("Lucida Grande"); |
|
165 desc.setFamily(family); |
|
166 desc.setSpecifiedSize((float)size); |
|
167 desc.setComputedSize((float)size); |
|
168 Font result = Font(desc, 0, 0); |
|
169 result.update(); |
|
170 return result; |
|
171 } |
|
172 |
|
173 DragImageRef WebDragClient::createDragImageForLink(KURL& url, const String& inLabel, Frame*) |
|
174 { |
|
175 //This is more or less an exact match for the MacOS code |
|
176 static const Font labelFont = dragLabelFont(DRAG_LINK_LABEL_FONT_SIZE, true); |
|
177 static const Font urlFont = dragLabelFont(DRAG_LINK_URL_FONT_SIZE, false); |
|
178 bool drawURLString = true; |
|
179 bool clipURLString = false; |
|
180 bool clipLabelString = false; |
|
181 |
|
182 String urlString = url.url(); |
|
183 String label = inLabel; |
|
184 if (label.isEmpty()) { |
|
185 drawURLString = false; |
|
186 label = urlString; |
|
187 } |
|
188 |
|
189 //First step in drawing the link drag image width |
|
190 TextRun labelRun(label.impl()); |
|
191 TextRun urlRun(urlString.impl()); |
|
192 IntSize labelSize(labelFont.width(labelRun), labelFont.ascent() + labelFont.descent()); |
|
193 |
|
194 if (labelSize.width() > MAX_DRAG_LABEL_STRING_WIDTH){ |
|
195 labelSize.setWidth(MAX_DRAG_LABEL_STRING_WIDTH); |
|
196 clipLabelString = true; |
|
197 } |
|
198 |
|
199 IntSize urlStringSize; |
|
200 IntSize imageSize(labelSize.width() + DRAG_LABEL_BORDER_X * 2, |
|
201 labelSize.height() + DRAG_LABEL_BORDER_Y * 2); |
|
202 |
|
203 if (drawURLString) { |
|
204 urlStringSize.setWidth(urlFont.width(urlRun)); |
|
205 urlStringSize.setHeight(urlFont.ascent() + urlFont.descent()); |
|
206 imageSize.setHeight(imageSize.height() + urlStringSize.height()); |
|
207 if (urlStringSize.width() > MAX_DRAG_LABEL_STRING_WIDTH) { |
|
208 imageSize.setWidth(MAX_DRAG_LABEL_WIDTH); |
|
209 clipURLString = true; |
|
210 } else { |
|
211 imageSize.setWidth(std::max(labelSize.width(), urlStringSize.width()) + DRAG_LABEL_BORDER_X * 2); |
|
212 } |
|
213 } |
|
214 |
|
215 // We now know how big the image needs to be, so we create and |
|
216 // fill the background |
|
217 HBITMAP image = 0; |
|
218 HDC dc = GetDC(0); |
|
219 HDC workingDC = CreateCompatibleDC(dc); |
|
220 if (!workingDC) { |
|
221 ReleaseDC(0, dc); |
|
222 return 0; |
|
223 } |
|
224 |
|
225 CGContextRef contextRef; |
|
226 image = allocImage(workingDC, imageSize, &contextRef); |
|
227 if (!image) { |
|
228 DeleteDC(workingDC); |
|
229 ReleaseDC(0, dc); |
|
230 return 0; |
|
231 } |
|
232 |
|
233 ::SelectObject(workingDC, image); |
|
234 GraphicsContext context(contextRef); |
|
235 // On Mac alpha is {0.7, 0.7, 0.7, 0.8}, however we can't control alpha |
|
236 // for drag images on win, so we use 1 |
|
237 static const Color backgroundColor(140, 140, 140); |
|
238 static const IntSize radii(DRAG_LABEL_RADIUS, DRAG_LABEL_RADIUS); |
|
239 context.setFont(labelFont); |
|
240 IntRect rect(0, 0, imageSize.width(), imageSize.height()); |
|
241 context.fillRoundedRect(rect, radii, radii, radii, radii, backgroundColor); |
|
242 |
|
243 // Draw the text |
|
244 static const Color topColor(0, 0, 0, 255); //original alpha = 0.75 |
|
245 static const Color bottomColor(255, 255, 255, 127); //original alpha = 0.5 |
|
246 if (drawURLString) { |
|
247 if (clipURLString) |
|
248 urlString = StringTruncator::rightTruncate(urlString, imageSize.width() - (DRAG_LABEL_BORDER_X * 2.0f), urlFont, false); |
|
249 IntPoint textPos(DRAG_LABEL_BORDER_X, imageSize.height() - (DRAG_LABEL_BORDER_Y_OFFSET + urlFont.descent())); |
|
250 WebCoreDrawDoubledTextAtPoint(context, urlString, textPos, urlFont, topColor, bottomColor); |
|
251 } |
|
252 |
|
253 if (clipLabelString) |
|
254 label = StringTruncator::rightTruncate(label, imageSize.width() - (DRAG_LABEL_BORDER_X * 2.0f), labelFont, false); |
|
255 |
|
256 IntPoint textPos(DRAG_LABEL_BORDER_X, DRAG_LABEL_BORDER_Y + labelFont.pixelSize()); |
|
257 WebCoreDrawDoubledTextAtPoint(context, label, textPos, labelFont, topColor, bottomColor); |
|
258 |
|
259 CGContextRelease(contextRef); |
|
260 DeleteDC(workingDC); |
|
261 ReleaseDC(0, dc); |
|
262 return image; |
|
263 } |
|
264 |
|
265 void WebDragClient::dragControllerDestroyed() |
|
266 { |
|
267 delete this; |
|
268 } |