File inputs only accept UTI types that can be inserted into contenteditable areas...
[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::canSmartReplace() const
113 {
114     return Pasteboard(m_pasteboardName).canSmartReplace();
115 }
116
117 bool DragData::containsColor() const
118 {
119     Vector<String> types;
120     platformStrategies()->pasteboardStrategy()->getTypes(types, m_pasteboardName);
121     return types.contains(colorPasteboardType());
122 }
123
124 bool DragData::containsFiles() const
125 {
126     Vector<String> types;
127     platformStrategies()->pasteboardStrategy()->getTypes(types, m_pasteboardName);
128     for (auto& type : types) {
129 #if PLATFORM(MAC)
130         if (type == String(NSFilesPromisePboardType) || type == String(NSFilenamesPboardType))
131             return true;
132 #else
133         if (UTTypeConformsTo(type.createCFString().autorelease(), kUTTypeContent))
134             return true;
135 #endif
136     }
137     return false;
138 }
139
140 unsigned DragData::numberOfFiles() const
141 {
142     return platformStrategies()->pasteboardStrategy()->getNumberOfFiles(m_pasteboardName);
143 }
144
145 void DragData::asFilenames(Vector<String>& result) const
146 {
147 #if PLATFORM(MAC)
148     platformStrategies()->pasteboardStrategy()->getPathnamesForType(result, String(NSFilenamesPboardType), m_pasteboardName);
149 #endif
150 #if PLATFORM(MAC) || ENABLE(DATA_INTERACTION)
151     if (!result.size())
152         result = fileNames();
153 #else
154     UNUSED_PARAM(result);
155 #endif
156 }
157
158 bool DragData::containsPlainText() const
159 {
160     Vector<String> types;
161     platformStrategies()->pasteboardStrategy()->getTypes(types, m_pasteboardName);
162
163     return types.contains(stringPasteboardType())
164         || types.contains(rtfdPasteboardType())
165         || types.contains(rtfPasteboardType())
166 #if PLATFORM(MAC)
167         || types.contains(String(NSFilenamesPboardType))
168 #endif
169         || platformStrategies()->pasteboardStrategy()->stringForType(urlPasteboardType(), m_pasteboardName).length();
170 }
171
172 String DragData::asPlainText() const
173 {
174     Pasteboard pasteboard(m_pasteboardName);
175     PasteboardPlainText text;
176     pasteboard.read(text);
177     String string = text.text;
178
179     // FIXME: It's not clear this is 100% correct since we know -[NSURL URLWithString:] does not handle
180     // all the same cases we handle well in the URL code for creating an NSURL.
181     if (text.isURL)
182         return userVisibleString([NSURL URLWithString:string]);
183
184     // FIXME: WTF should offer a non-Mac-specific way to convert string to precomposed form so we can do it for all platforms.
185     return [(NSString *)string precomposedStringWithCanonicalMapping];
186 }
187
188 Color DragData::asColor() const
189 {
190     return platformStrategies()->pasteboardStrategy()->color(m_pasteboardName);
191 }
192
193 bool DragData::containsCompatibleContent(DraggingPurpose purpose) const
194 {
195     if (purpose == DraggingPurpose::ForFileUpload)
196         return containsFiles();
197
198     Vector<String> types;
199     platformStrategies()->pasteboardStrategy()->getTypes(types, m_pasteboardName);
200     return types.contains(String(WebArchivePboardType))
201         || types.contains(htmlPasteboardType())
202 #if PLATFORM(MAC)
203         || types.contains(String(NSFilenamesPboardType))
204         || types.contains(String(NSFilesPromisePboardType))
205 #endif
206         || types.contains(tiffPasteboardType())
207         || types.contains(pdfPasteboardType())
208         || types.contains(urlPasteboardType())
209         || types.contains(rtfdPasteboardType())
210         || types.contains(rtfPasteboardType())
211         || types.contains(String(kUTTypeUTF8PlainText))
212         || types.contains(stringPasteboardType())
213         || types.contains(colorPasteboardType())
214         || types.contains(String(kUTTypeJPEG))
215         || types.contains(String(kUTTypePNG));
216 }
217
218 bool DragData::containsPromise() const
219 {
220     Vector<String> files;
221 #if PLATFORM(MAC)
222     platformStrategies()->pasteboardStrategy()->getPathnamesForType(files, String(NSFilesPromisePboardType), m_pasteboardName);
223 #endif
224     return files.size() == 1;
225 }
226
227 #if !ENABLE(DATA_INTERACTION)
228
229 bool DragData::containsURL(FilenameConversionPolicy filenamePolicy) const
230 {
231     return !asURL(filenamePolicy).isEmpty();
232 }
233
234 #endif
235
236 String DragData::asURL(FilenameConversionPolicy, String* title) const
237 {
238     // FIXME: Use filenamePolicy.
239
240     if (title) {
241 #if PLATFORM(MAC)
242         String URLTitleString = platformStrategies()->pasteboardStrategy()->stringForType(String(WebURLNamePboardType), m_pasteboardName);
243         if (!URLTitleString.isEmpty())
244             *title = URLTitleString;
245 #endif
246     }
247     
248     Vector<String> types;
249     platformStrategies()->pasteboardStrategy()->getTypes(types, m_pasteboardName);
250
251     if (types.contains(urlPasteboardType())) {
252         NSURL *URLFromPasteboard = [NSURL URLWithString:platformStrategies()->pasteboardStrategy()->stringForType(urlPasteboardType(), m_pasteboardName)];
253         NSString *scheme = [URLFromPasteboard scheme];
254         // Cannot drop other schemes unless <rdar://problem/10562662> and <rdar://problem/11187315> are fixed.
255         if ([scheme isEqualToString:@"http"] || [scheme isEqualToString:@"https"])
256             return [URLByCanonicalizingURL(URLFromPasteboard) absoluteString];
257     }
258     
259     if (types.contains(stringPasteboardType())) {
260         NSURL *URLFromPasteboard = [NSURL URLWithString:platformStrategies()->pasteboardStrategy()->stringForType(stringPasteboardType(), m_pasteboardName)];
261         NSString *scheme = [URLFromPasteboard scheme];
262         // 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.
263         // The result of this function is used to initiate navigation, so we shouldn't allow arbitrary file URLs.
264         // FIXME: Should we allow only http family schemes, or anything non-local?
265         if ([scheme isEqualToString:@"http"] || [scheme isEqualToString:@"https"])
266             return [URLByCanonicalizingURL(URLFromPasteboard) absoluteString];
267     }
268     
269 #if PLATFORM(MAC)
270     if (types.contains(String(NSFilenamesPboardType))) {
271         Vector<String> files;
272         platformStrategies()->pasteboardStrategy()->getPathnamesForType(files, String(NSFilenamesPboardType), m_pasteboardName);
273         if (files.size() == 1) {
274             BOOL isDirectory;
275             if ([[NSFileManager defaultManager] fileExistsAtPath:files[0] isDirectory:&isDirectory] && isDirectory)
276                 return String();
277             return [URLByCanonicalizingURL([NSURL fileURLWithPath:files[0]]) absoluteString];
278         }
279     }
280
281     if (types.contains(String(NSFilesPromisePboardType)) && fileNames().size() == 1)
282         return [URLByCanonicalizingURL([NSURL fileURLWithPath:fileNames()[0]]) absoluteString];
283 #endif
284
285     return String();        
286 }
287
288 } // namespace WebCore
289
290 #endif // ENABLE(DRAG_SUPPORT)