20d129d067fc784ff5d1d3fefade4889480fee90
[WebKit.git] / Source / WebCore / platform / mac / DragDataMac.mm
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 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 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 #import "config.h"
27 #import "DragData.h"
28
29 #if ENABLE(DRAG_SUPPORT)
30 #import "MIMETypeRegistry.h"
31 #import "Pasteboard.h"
32 #import "PasteboardStrategy.h"
33 #import "PlatformStrategies.h"
34 #import "WebCoreNSURLExtras.h"
35
36 #if USE(APPLE_INTERNAL_SDK)
37
38 #import <WebKitAdditions/DragDataAdditions.mm>
39
40 #else
41
42 static inline String rtfPasteboardType()
43 {
44     return String(NSRTFPboardType);
45 }
46
47 static inline String rtfdPasteboardType()
48 {
49     return String(NSRTFDPboardType);
50 }
51
52 static inline String stringPasteboardType()
53 {
54     return String(NSStringPboardType);
55 }
56
57 static inline String urlPasteboardType()
58 {
59     return String(NSURLPboardType);
60 }
61
62 static inline String htmlPasteboardType()
63 {
64     return String(NSHTMLPboardType);
65 }
66
67 static inline String colorPasteboardType()
68 {
69     return String(NSColorPboardType);
70 }
71
72 static inline String pdfPasteboardType()
73 {
74     return String(NSPDFPboardType);
75 }
76
77 static inline String tiffPasteboardType()
78 {
79     return String(NSTIFFPboardType);
80 }
81
82 #endif // USE(APPLE_INTERNAL_SDK)
83
84 namespace WebCore {
85
86 DragData::DragData(DragDataRef data, const IntPoint& clientPosition, const IntPoint& globalPosition, DragOperation sourceOperationMask, DragApplicationFlags flags, DragDestinationAction destinationAction)
87     : m_clientPosition(clientPosition)
88     , m_globalPosition(globalPosition)
89     , m_platformDragData(data)
90     , m_draggingSourceOperationMask(sourceOperationMask)
91     , m_applicationFlags(flags)
92     , m_dragDestinationAction(destinationAction)
93 #if PLATFORM(MAC)
94     , m_pasteboardName([[m_platformDragData draggingPasteboard] name])
95 #else
96     , m_pasteboardName("data interaction pasteboard")
97 #endif
98 {
99 }
100
101 DragData::DragData(const String& dragStorageName, const IntPoint& clientPosition, const IntPoint& globalPosition, DragOperation sourceOperationMask, DragApplicationFlags flags, DragDestinationAction destinationAction)
102     : m_clientPosition(clientPosition)
103     , m_globalPosition(globalPosition)
104     , m_platformDragData(0)
105     , m_draggingSourceOperationMask(sourceOperationMask)
106     , m_applicationFlags(flags)
107     , m_dragDestinationAction(destinationAction)
108     , m_pasteboardName(dragStorageName)
109 {
110 }
111
112 bool DragData::containsURLTypeIdentifier() const
113 {
114     Vector<String> types;
115     platformStrategies()->pasteboardStrategy()->getTypes(types, m_pasteboardName);
116     return types.contains(urlPasteboardType());
117 }
118     
119 bool DragData::canSmartReplace() const
120 {
121     return Pasteboard(m_pasteboardName).canSmartReplace();
122 }
123
124 bool DragData::containsColor() const
125 {
126     Vector<String> types;
127     platformStrategies()->pasteboardStrategy()->getTypes(types, m_pasteboardName);
128     return types.contains(colorPasteboardType());
129 }
130
131 bool DragData::containsFiles() const
132 {
133     Vector<String> types;
134     platformStrategies()->pasteboardStrategy()->getTypes(types, m_pasteboardName);
135     for (auto& type : types) {
136 #if PLATFORM(MAC)
137         if (type == String(NSFilesPromisePboardType) || type == String(NSFilenamesPboardType))
138             return true;
139 #else
140         if (UTTypeConformsTo(type.createCFString().autorelease(), kUTTypeContent))
141             return true;
142 #endif
143     }
144     return false;
145 }
146
147 unsigned DragData::numberOfFiles() const
148 {
149     return platformStrategies()->pasteboardStrategy()->getNumberOfFiles(m_pasteboardName);
150 }
151
152 void DragData::asFilenames(Vector<String>& result) const
153 {
154 #if PLATFORM(MAC)
155     platformStrategies()->pasteboardStrategy()->getPathnamesForType(result, String(NSFilenamesPboardType), m_pasteboardName);
156 #endif
157 #if PLATFORM(MAC) || ENABLE(DATA_INTERACTION)
158     if (!result.size())
159         result = fileNames();
160 #else
161     UNUSED_PARAM(result);
162 #endif
163 }
164
165 bool DragData::containsPlainText() const
166 {
167     Vector<String> types;
168     platformStrategies()->pasteboardStrategy()->getTypes(types, m_pasteboardName);
169
170     return types.contains(stringPasteboardType())
171         || types.contains(rtfdPasteboardType())
172         || types.contains(rtfPasteboardType())
173 #if PLATFORM(MAC)
174         || types.contains(String(NSFilenamesPboardType))
175 #endif
176         || platformStrategies()->pasteboardStrategy()->stringForType(urlPasteboardType(), m_pasteboardName).length();
177 }
178
179 String DragData::asPlainText() const
180 {
181     Pasteboard pasteboard(m_pasteboardName);
182     PasteboardPlainText text;
183     pasteboard.read(text);
184     String string = text.text;
185
186     // FIXME: It's not clear this is 100% correct since we know -[NSURL URLWithString:] does not handle
187     // all the same cases we handle well in the URL code for creating an NSURL.
188     if (text.isURL)
189         return userVisibleString([NSURL URLWithString:string]);
190
191     // FIXME: WTF should offer a non-Mac-specific way to convert string to precomposed form so we can do it for all platforms.
192     return [(NSString *)string precomposedStringWithCanonicalMapping];
193 }
194
195 Color DragData::asColor() const
196 {
197     return platformStrategies()->pasteboardStrategy()->color(m_pasteboardName);
198 }
199
200 bool DragData::containsCompatibleContent(DraggingPurpose purpose) const
201 {
202     if (purpose == DraggingPurpose::ForFileUpload)
203         return containsFiles();
204
205     Vector<String> types;
206     platformStrategies()->pasteboardStrategy()->getTypes(types, m_pasteboardName);
207     return types.contains(String(WebArchivePboardType))
208         || types.contains(htmlPasteboardType())
209 #if PLATFORM(MAC)
210         || types.contains(String(NSFilenamesPboardType))
211         || types.contains(String(NSFilesPromisePboardType))
212 #endif
213         || types.contains(tiffPasteboardType())
214         || types.contains(pdfPasteboardType())
215         || types.contains(urlPasteboardType())
216         || types.contains(rtfdPasteboardType())
217         || types.contains(rtfPasteboardType())
218         || types.contains(String(kUTTypeUTF8PlainText))
219         || types.contains(stringPasteboardType())
220         || types.contains(colorPasteboardType())
221         || types.contains(String(kUTTypeJPEG))
222         || types.contains(String(kUTTypePNG));
223 }
224
225 bool DragData::containsPromise() const
226 {
227     Vector<String> files;
228 #if PLATFORM(MAC)
229     platformStrategies()->pasteboardStrategy()->getPathnamesForType(files, String(NSFilesPromisePboardType), m_pasteboardName);
230 #endif
231     return files.size() == 1;
232 }
233
234 #if !ENABLE(DATA_INTERACTION)
235
236 bool DragData::containsURL(FilenameConversionPolicy filenamePolicy) const
237 {
238     return !asURL(filenamePolicy).isEmpty();
239 }
240
241 #endif
242
243 String DragData::asURL(FilenameConversionPolicy, String* title) const
244 {
245     // FIXME: Use filenamePolicy.
246
247     if (title) {
248 #if PLATFORM(MAC)
249         String URLTitleString = platformStrategies()->pasteboardStrategy()->stringForType(String(WebURLNamePboardType), m_pasteboardName);
250         if (!URLTitleString.isEmpty())
251             *title = URLTitleString;
252 #endif
253     }
254     
255     Vector<String> types;
256     platformStrategies()->pasteboardStrategy()->getTypes(types, m_pasteboardName);
257
258     if (types.contains(urlPasteboardType())) {
259         NSURL *URLFromPasteboard = [NSURL URLWithString:platformStrategies()->pasteboardStrategy()->stringForType(urlPasteboardType(), m_pasteboardName)];
260         NSString *scheme = [URLFromPasteboard scheme];
261         // Cannot drop other schemes unless <rdar://problem/10562662> and <rdar://problem/11187315> are fixed.
262         if ([scheme isEqualToString:@"http"] || [scheme isEqualToString:@"https"])
263             return [URLByCanonicalizingURL(URLFromPasteboard) absoluteString];
264     }
265     
266     if (types.contains(stringPasteboardType())) {
267         NSURL *URLFromPasteboard = [NSURL URLWithString:platformStrategies()->pasteboardStrategy()->stringForType(stringPasteboardType(), m_pasteboardName)];
268         NSString *scheme = [URLFromPasteboard scheme];
269         // Pasteboard content is not trusted, because JavaScript code can modify it. We can sanitize it for URLs and other typed content, but not for strings.
270         // The result of this function is used to initiate navigation, so we shouldn't allow arbitrary file URLs.
271         // FIXME: Should we allow only http family schemes, or anything non-local?
272         if ([scheme isEqualToString:@"http"] || [scheme isEqualToString:@"https"])
273             return [URLByCanonicalizingURL(URLFromPasteboard) absoluteString];
274     }
275     
276 #if PLATFORM(MAC)
277     if (types.contains(String(NSFilenamesPboardType))) {
278         Vector<String> files;
279         platformStrategies()->pasteboardStrategy()->getPathnamesForType(files, String(NSFilenamesPboardType), m_pasteboardName);
280         if (files.size() == 1) {
281             BOOL isDirectory;
282             if ([[NSFileManager defaultManager] fileExistsAtPath:files[0] isDirectory:&isDirectory] && isDirectory)
283                 return String();
284             return [URLByCanonicalizingURL([NSURL fileURLWithPath:files[0]]) absoluteString];
285         }
286     }
287
288     if (types.contains(String(NSFilesPromisePboardType)) && fileNames().size() == 1)
289         return [URLByCanonicalizingURL([NSURL fileURLWithPath:fileNames()[0]]) absoluteString];
290 #endif
291
292     return String();        
293 }
294
295 } // namespace WebCore
296
297 #endif // ENABLE(DRAG_SUPPORT)