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