[iOS] Upstream PLATFORM(IOS) changes to Source/WebKit/
[WebKit-https.git] / Source / WebKit / mac / Misc / WebNSPasteboardExtras.mm
1 /*
2  * Copyright (C) 2005, 2006, 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  *
8  * 1.  Redistributions of source code must retain the above copyright
9  *     notice, this list of conditions and the following disclaimer. 
10  * 2.  Redistributions in binary form must reproduce the above copyright
11  *     notice, this list of conditions and the following disclaimer in the
12  *     documentation and/or other materials provided with the distribution. 
13  * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
14  *     its contributors may be used to endorse or promote products derived
15  *     from this software without specific prior written permission. 
16  *
17  * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
18  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20  * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
21  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  */
28
29 #if !PLATFORM(IOS)
30
31 #import "WebNSPasteboardExtras.h"
32
33 #import "DOMElementInternal.h"
34 #import "WebArchive.h"
35 #import "WebFrameInternal.h"
36 #import "WebHTMLViewInternal.h"
37 #import "WebNSURLExtras.h"
38 #import "WebResourcePrivate.h"
39 #import "WebURLsWithTitles.h"
40 #import "WebViewPrivate.h"
41 #import <WebCore/CachedImage.h>
42 #import <WebCore/Element.h>
43 #import <WebCore/Image.h>
44 #import <WebCore/MIMETypeRegistry.h>
45 #import <WebCore/RenderImage.h>
46 #import <WebKit/DOMExtensions.h>
47 #import <WebKit/DOMPrivate.h>
48 #import <WebKitSystemInterface.h>
49 #import <wtf/Assertions.h>
50 #import <wtf/RetainPtr.h>
51 #import <wtf/StdLibExtras.h>
52
53 using namespace WebCore;
54
55 NSString *WebURLPboardType = @"public.url";
56 NSString *WebURLNamePboardType = @"public.url-name";
57
58 @implementation NSPasteboard (WebExtras)
59
60 + (NSArray *)_web_writableTypesForURL
61 {
62     DEFINE_STATIC_LOCAL(RetainPtr<NSArray>, types, ([[NSArray alloc] initWithObjects:
63         WebURLsWithTitlesPboardType,
64         NSURLPboardType,
65         WebURLPboardType,
66         WebURLNamePboardType,
67         NSStringPboardType,
68         nil]));
69     return types.get();
70 }
71
72 static inline NSArray *_createWritableTypesForImageWithoutArchive()
73 {
74     NSMutableArray *types = [[NSMutableArray alloc] initWithObjects:NSTIFFPboardType, nil];
75     [types addObjectsFromArray:[NSPasteboard _web_writableTypesForURL]];
76     return types;
77 }
78
79 static NSArray *_writableTypesForImageWithoutArchive (void)
80 {
81     DEFINE_STATIC_LOCAL(RetainPtr<NSArray>, types, (_createWritableTypesForImageWithoutArchive()));
82     return types.get();
83 }
84
85 static inline NSArray *_createWritableTypesForImageWithArchive()
86 {
87     NSMutableArray *types = [_writableTypesForImageWithoutArchive() mutableCopy];
88     [types addObject:NSRTFDPboardType];
89     [types addObject:WebArchivePboardType];
90     return types;
91 }
92
93 static NSArray *_writableTypesForImageWithArchive (void)
94 {
95     DEFINE_STATIC_LOCAL(RetainPtr<NSArray>, types, (_createWritableTypesForImageWithArchive()));
96     return types.get();
97 }
98
99 + (NSArray *)_web_writableTypesForImageIncludingArchive:(BOOL)hasArchive
100 {
101     return hasArchive 
102         ? _writableTypesForImageWithArchive()
103         : _writableTypesForImageWithoutArchive();
104 }
105
106 + (NSArray *)_web_dragTypesForURL
107 {
108     return [NSArray arrayWithObjects:
109         WebURLsWithTitlesPboardType,
110         NSURLPboardType,
111         WebURLPboardType,
112         WebURLNamePboardType,
113         NSStringPboardType,
114         NSFilenamesPboardType,
115         nil];
116 }
117
118 - (NSURL *)_web_bestURL
119 {
120     NSArray *types = [self types];
121
122     if ([types containsObject:NSURLPboardType]) {
123         NSURL *URLFromPasteboard = [NSURL URLFromPasteboard:self];
124         NSString *scheme = [URLFromPasteboard scheme];
125         if ([scheme isEqualToString:@"http"] || [scheme isEqualToString:@"https"]) {
126             return [URLFromPasteboard _webkit_canonicalize];
127         }
128     }
129
130     if ([types containsObject:NSStringPboardType]) {
131         NSString *URLString = [self stringForType:NSStringPboardType];
132         if ([URLString _webkit_looksLikeAbsoluteURL]) {
133             NSURL *URL = [[NSURL _web_URLWithUserTypedString:URLString] _webkit_canonicalize];
134             if (URL) {
135                 return URL;
136             }
137         }
138     }
139
140     if ([types containsObject:NSFilenamesPboardType]) {
141         NSArray *files = [self propertyListForType:NSFilenamesPboardType];
142         // FIXME: Maybe it makes more sense to allow multiple files and only use the first one?
143         if ([files count] == 1) {
144             NSString *file = [files objectAtIndex:0];
145             // FIXME: We are filtering out directories because that's what the original code used to
146             // do. Without this check, if the URL points to a local directory, Safari will open the
147             // parent directory of the directory in Finder. This check should go away as soon as
148             // possible.
149             BOOL isDirectory;
150             if ([[NSFileManager defaultManager] fileExistsAtPath:file isDirectory:&isDirectory] && isDirectory)
151                 return nil;
152             return [[NSURL fileURLWithPath:file] _webkit_canonicalize];
153         }
154     }
155
156     return nil;
157 }
158
159 - (void)_web_writeURL:(NSURL *)URL andTitle:(NSString *)title types:(NSArray *)types
160 {
161     ASSERT(URL);
162
163     if ([title length] == 0) {
164         title = [[URL path] lastPathComponent];
165         if ([title length] == 0)
166             title = [URL _web_userVisibleString];
167     }
168     
169     if ([types containsObject:NSURLPboardType])
170         [URL writeToPasteboard:self];
171     if ([types containsObject:WebURLPboardType])
172         [self setString:[URL _web_originalDataAsString] forType:WebURLPboardType];
173     if ([types containsObject:WebURLNamePboardType])
174         [self setString:title forType:WebURLNamePboardType];
175     if ([types containsObject:NSStringPboardType])
176         [self setString:[URL _web_userVisibleString] forType:NSStringPboardType];
177     if ([types containsObject:WebURLsWithTitlesPboardType])
178         [WebURLsWithTitles writeURLs:[NSArray arrayWithObject:URL] andTitles:[NSArray arrayWithObject:title] toPasteboard:self];
179 }
180
181 + (int)_web_setFindPasteboardString:(NSString *)string withOwner:(id)owner
182 {
183     NSPasteboard *findPasteboard = [NSPasteboard pasteboardWithName:NSFindPboard];
184     [findPasteboard declareTypes:[NSArray arrayWithObject:NSStringPboardType] owner:owner];
185     [findPasteboard setString:string forType:NSStringPboardType];
186     return [findPasteboard changeCount];
187 }
188
189 - (void)_web_writeFileWrapperAsRTFDAttachment:(NSFileWrapper *)wrapper
190 {
191     NSTextAttachment *attachment = [[NSTextAttachment alloc] initWithFileWrapper:wrapper];
192     
193     NSAttributedString *string = [NSAttributedString attributedStringWithAttachment:attachment];
194     [attachment release];
195     
196     NSData *RTFDData = [string RTFDFromRange:NSMakeRange(0, [string length]) documentAttributes:nil];
197     [self setData:RTFDData forType:NSRTFDPboardType];
198 }
199
200
201 - (void)_web_writePromisedRTFDFromArchive:(WebArchive*)archive containsImage:(BOOL)containsImage
202 {
203     ASSERT(archive);
204     // This image data is either the only subresource of an archive (HTML image case)
205     // or the main resource (standalone image case).
206     NSArray *subresources = [archive subresources];
207     WebResource *resource = [archive mainResource];
208     if (containsImage && [subresources count] > 0 
209         && MIMETypeRegistry::isSupportedImageResourceMIMEType([[subresources objectAtIndex:0] MIMEType]))
210         resource = (WebResource *)[subresources objectAtIndex:0];
211     ASSERT(resource != nil);
212     
213     ASSERT(!containsImage || MIMETypeRegistry::isSupportedImageResourceMIMEType([resource MIMEType]));
214     if (!containsImage || MIMETypeRegistry::isSupportedImageResourceMIMEType([resource MIMEType]))
215         [self _web_writeFileWrapperAsRTFDAttachment:[resource _fileWrapperRepresentation]];
216     
217 }
218
219 static CachedImage* imageFromElement(DOMElement *domElement)
220 {
221     Element* element = core(domElement);
222     if (!element)
223         return 0;
224     
225     RenderObject* renderer = element->renderer();
226     RenderImage* imageRenderer = toRenderImage(renderer);
227     if (!imageRenderer->cachedImage() || imageRenderer->cachedImage()->errorOccurred()) 
228         return 0;        
229     return imageRenderer->cachedImage();
230 }
231
232 - (void)_web_writeImage:(NSImage *)image
233                 element:(DOMElement *)element
234                     URL:(NSURL *)URL 
235                   title:(NSString *)title
236                 archive:(WebArchive *)archive
237                   types:(NSArray *)types
238                  source:(WebHTMLView *)source
239 {
240     ASSERT(image || element);
241     ASSERT(URL);
242
243     [self _web_writeURL:URL andTitle:title types:types];
244     
245     if ([types containsObject:NSTIFFPboardType]) {
246         if (image)
247             [self setData:[image TIFFRepresentation] forType:NSTIFFPboardType];
248         else if (source && element)
249             [source setPromisedDragTIFFDataSource:imageFromElement(element)];
250         else if (element)
251             [self setData:[element _imageTIFFRepresentation] forType:NSTIFFPboardType];
252     }
253     
254     if (archive) {
255         if ([types containsObject:WebArchivePboardType])
256             [self setData:[archive data] forType:WebArchivePboardType];
257         return;
258     }
259
260     // We should not have declared types that we aren't going to write (4031826).
261     ASSERT(![types containsObject:NSRTFDPboardType]);
262     ASSERT(![types containsObject:WebArchivePboardType]);
263 }
264
265 - (id)_web_declareAndWriteDragImageForElement:(DOMElement *)element
266                                        URL:(NSURL *)URL 
267                                      title:(NSString *)title
268                                    archive:(WebArchive *)archive
269                                     source:(WebHTMLView *)source
270 {
271     ASSERT(self == [NSPasteboard pasteboardWithName:NSDragPboard]);
272
273     NSString *extension = @"";
274     if (RenderObject* renderer = core(element)->renderer()) {
275         if (renderer->isImage()) {
276             if (CachedImage* image = toRenderImage(renderer)->cachedImage()) {
277                 extension = image->image()->filenameExtension();
278                 if (![extension length])
279                     return 0;
280             }
281         }
282     }
283
284     NSMutableArray *types = [[NSMutableArray alloc] initWithObjects:NSFilesPromisePboardType, nil];
285     [types addObjectsFromArray:[NSPasteboard _web_writableTypesForImageIncludingArchive:(archive != nil)]];
286     [self declareTypes:types owner:source];    
287     [self _web_writeImage:nil element:element URL:URL title:title archive:archive types:types source:source];
288     [types release];
289
290     NSArray *extensions = [[NSArray alloc] initWithObjects:extension, nil];
291     [self setPropertyList:extensions forType:NSFilesPromisePboardType];
292     [extensions release];
293
294     return source;
295 }
296
297 @end
298
299 #endif // !PLATFORM(IOS)