[WK2] Support data interaction of files into file inputs
[WebKit-https.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() const
194 {
195     Vector<String> types;
196     platformStrategies()->pasteboardStrategy()->getTypes(types, m_pasteboardName);
197     return types.contains(String(WebArchivePboardType))
198         || types.contains(htmlPasteboardType())
199 #if PLATFORM(MAC)
200         || types.contains(String(NSFilenamesPboardType))
201         || types.contains(String(NSFilesPromisePboardType))
202 #endif
203         || types.contains(tiffPasteboardType())
204         || types.contains(pdfPasteboardType())
205         || types.contains(urlPasteboardType())
206         || types.contains(rtfdPasteboardType())
207         || types.contains(rtfPasteboardType())
208         || types.contains(String(kUTTypeUTF8PlainText))
209         || types.contains(stringPasteboardType())
210         || types.contains(colorPasteboardType())
211         || types.contains(String(kUTTypeJPEG))
212         || types.contains(String(kUTTypePNG));
213 }
214
215 bool DragData::containsPromise() const
216 {
217     Vector<String> files;
218 #if PLATFORM(MAC)
219     platformStrategies()->pasteboardStrategy()->getPathnamesForType(files, String(NSFilesPromisePboardType), m_pasteboardName);
220 #endif
221     return files.size() == 1;
222 }
223
224 #if !ENABLE(DATA_INTERACTION)
225
226 bool DragData::containsURL(FilenameConversionPolicy filenamePolicy) const
227 {
228     return !asURL(filenamePolicy).isEmpty();
229 }
230
231 #endif
232
233 String DragData::asURL(FilenameConversionPolicy, String* title) const
234 {
235     // FIXME: Use filenamePolicy.
236
237     if (title) {
238 #if PLATFORM(MAC)
239         String URLTitleString = platformStrategies()->pasteboardStrategy()->stringForType(String(WebURLNamePboardType), m_pasteboardName);
240         if (!URLTitleString.isEmpty())
241             *title = URLTitleString;
242 #endif
243     }
244     
245     Vector<String> types;
246     platformStrategies()->pasteboardStrategy()->getTypes(types, m_pasteboardName);
247
248     if (types.contains(urlPasteboardType())) {
249         NSURL *URLFromPasteboard = [NSURL URLWithString:platformStrategies()->pasteboardStrategy()->stringForType(urlPasteboardType(), m_pasteboardName)];
250         NSString *scheme = [URLFromPasteboard scheme];
251         // Cannot drop other schemes unless <rdar://problem/10562662> and <rdar://problem/11187315> are fixed.
252         if ([scheme isEqualToString:@"http"] || [scheme isEqualToString:@"https"])
253             return [URLByCanonicalizingURL(URLFromPasteboard) absoluteString];
254     }
255     
256     if (types.contains(stringPasteboardType())) {
257         NSURL *URLFromPasteboard = [NSURL URLWithString:platformStrategies()->pasteboardStrategy()->stringForType(stringPasteboardType(), m_pasteboardName)];
258         NSString *scheme = [URLFromPasteboard scheme];
259         // 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.
260         // The result of this function is used to initiate navigation, so we shouldn't allow arbitrary file URLs.
261         // FIXME: Should we allow only http family schemes, or anything non-local?
262         if ([scheme isEqualToString:@"http"] || [scheme isEqualToString:@"https"])
263             return [URLByCanonicalizingURL(URLFromPasteboard) absoluteString];
264     }
265     
266 #if PLATFORM(MAC)
267     if (types.contains(String(NSFilenamesPboardType))) {
268         Vector<String> files;
269         platformStrategies()->pasteboardStrategy()->getPathnamesForType(files, String(NSFilenamesPboardType), m_pasteboardName);
270         if (files.size() == 1) {
271             BOOL isDirectory;
272             if ([[NSFileManager defaultManager] fileExistsAtPath:files[0] isDirectory:&isDirectory] && isDirectory)
273                 return String();
274             return [URLByCanonicalizingURL([NSURL fileURLWithPath:files[0]]) absoluteString];
275         }
276     }
277
278     if (types.contains(String(NSFilesPromisePboardType)) && fileNames().size() == 1)
279         return [URLByCanonicalizingURL([NSURL fileURLWithPath:fileNames()[0]]) absoluteString];
280 #endif
281
282     return String();        
283 }
284
285 } // namespace WebCore
286
287 #endif // ENABLE(DRAG_SUPPORT)