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