Reviewed by Don.
[WebKit-https.git] / WebKit / Misc.subproj / WebNSPasteboardExtras.m
1 /*
2  * Copyright (C) 2005 Apple Computer, 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 #import <WebKit/WebNSPasteboardExtras.h>
30
31 #import <WebKit/WebArchive.h>
32 #import <WebKit/WebAssertions.h>
33 #import <WebKit/WebImageRenderer.h>
34 #import <WebKit/WebImageRendererFactory.h>
35 #import <WebKit/WebNSURLExtras.h>
36 #import <WebKit/WebResourcePrivate.h>
37 #import <WebKit/WebURLsWithTitles.h>
38 #import <WebKit/WebViewPrivate.h>
39 #import <WebKitSystemInterface.h>
40
41 #import <HIServices/CoreTranslationFlavorTypeNames.h>
42
43 NSString *WebURLPboardType = nil;
44 NSString *WebURLNamePboardType = nil;
45
46 @interface NSFilePromiseDragSource : NSObject
47 - initWithSource:(id)draggingSource;
48 - (void)setTypes:(NSArray *)types onPasteboard:(NSPasteboard *)pboard;
49 @end
50
51 @implementation NSPasteboard (WebExtras)
52
53 + (void)initialize
54 {
55     CFStringRef osTypeString = UTCreateStringForOSType('url ');
56     CFStringRef utiTypeString = UTTypeCreatePreferredIdentifierForTag( kUTTagClassOSType, osTypeString, NULL );
57     WebURLPboardType = (NSString *)UTTypeCopyPreferredTagWithClass( kUTTagClassNSPboardType, utiTypeString );
58     
59     osTypeString = UTCreateStringForOSType('urln');
60     utiTypeString = UTTypeCreatePreferredIdentifierForTag( kUTTagClassOSType, osTypeString, NULL );
61     WebURLNamePboardType = (NSString *)UTTypeCopyPreferredTagWithClass( kUTTagClassNSPboardType, utiTypeString );
62 }
63
64 + (NSArray *)_web_writableTypesForURL
65 {
66     static NSArray *types = nil;
67     if (!types) {
68         types = [[NSArray alloc] initWithObjects:
69             WebURLsWithTitlesPboardType,
70             NSURLPboardType,
71             WebURLPboardType,
72             WebURLNamePboardType,
73             NSStringPboardType,
74             nil];
75     }
76     return types;
77 }
78
79 static NSArray *_writableTypesForImageWithoutArchive (void)
80 {
81     static NSMutableArray *types = nil;
82     if (types == nil) {
83         types = [[NSMutableArray alloc] initWithObjects:NSTIFFPboardType, nil];
84         [types addObjectsFromArray:[NSPasteboard _web_writableTypesForURL]];
85     }
86     return types;
87 }
88
89 static NSArray *_writableTypesForImageWithArchive (void)
90 {
91     static NSMutableArray *types = nil;
92     if (types == nil) {
93         types = [_writableTypesForImageWithoutArchive() mutableCopy];
94         [types addObject:NSRTFDPboardType];
95         [types addObject:WebArchivePboardType];
96     }
97     return types;
98 }
99
100 + (NSArray *)_web_writableTypesForImageIncludingArchive:(BOOL)hasArchive
101 {
102     return hasArchive 
103         ? _writableTypesForImageWithArchive()
104         : _writableTypesForImageWithoutArchive();
105 }
106
107 + (NSArray *)_web_dragTypesForURL
108 {
109     return [NSArray arrayWithObjects:
110         WebURLsWithTitlesPboardType,
111         NSURLPboardType,
112         WebURLPboardType,
113         WebURLNamePboardType,
114         NSStringPboardType,
115         NSFilenamesPboardType,
116         nil];
117 }
118
119 - (NSURL *)_web_bestURL
120 {
121     NSArray *types = [self types];
122
123     if ([types containsObject:NSURLPboardType]) {
124         NSURL *URLFromPasteboard = [NSURL URLFromPasteboard:self];
125         NSString *scheme = [URLFromPasteboard scheme];
126         if ([scheme isEqualToString:@"http"] || [scheme isEqualToString:@"https"]) {
127             return [URLFromPasteboard _webkit_canonicalize];
128         }
129     }
130
131     if ([types containsObject:NSStringPboardType]) {
132         NSString *URLString = [self stringForType:NSStringPboardType];
133         if ([URLString _webkit_looksLikeAbsoluteURL]) {
134             NSURL *URL = [[NSURL _web_URLWithUserTypedString:URLString] _webkit_canonicalize];
135             if (URL) {
136                 return URL;
137             }
138         }
139     }
140
141     if ([types containsObject:NSFilenamesPboardType]) {
142         NSArray *files = [self propertyListForType:NSFilenamesPboardType];
143         if ([files count] == 1) {
144             NSString *file = [files objectAtIndex:0];
145             BOOL isDirectory;
146             if([[NSFileManager defaultManager] fileExistsAtPath:file isDirectory:&isDirectory] && !isDirectory){
147                 if ([WebView canShowFile:file]) {
148                     return [[NSURL fileURLWithPath:file] _webkit_canonicalize];
149                 }
150             }
151         }
152     }
153
154     return nil;
155 }
156
157 - (void)_web_writeURL:(NSURL *)URL andTitle:(NSString *)title types:(NSArray *)types
158 {
159     ASSERT(URL);
160     
161     if ([title length] == 0) {
162         title = [[URL path] lastPathComponent];
163         if ([title length] == 0) {
164             title = [URL _web_userVisibleString];
165         }
166     }
167     
168     if ([types containsObject:NSURLPboardType]) {
169         [URL writeToPasteboard:self];
170     }
171     if ([types containsObject:WebURLPboardType]) {
172         [self setString:[URL _web_userVisibleString] forType:WebURLPboardType];
173     }
174     if ([types containsObject:WebURLNamePboardType]) {
175         [self setString:title forType:WebURLNamePboardType];
176     }
177     if ([types containsObject:NSStringPboardType]) {
178         [self setString:[URL _web_userVisibleString] forType:NSStringPboardType];
179     }
180     if ([types containsObject:WebURLsWithTitlesPboardType]) {
181         [WebURLsWithTitles writeURLs:[NSArray arrayWithObject:URL] andTitles:[NSArray arrayWithObject:title] toPasteboard:self];
182     }
183 }
184
185 + (int)_web_setFindPasteboardString:(NSString *)string withOwner:(id)owner
186 {
187     NSPasteboard *findPasteboard = [NSPasteboard pasteboardWithName:NSFindPboard];
188     [findPasteboard declareTypes:[NSArray arrayWithObject:NSStringPboardType] owner:owner];
189     [findPasteboard setString:string forType:NSStringPboardType];
190     return [findPasteboard changeCount];
191 }
192
193 - (void)_web_writeFileWrapperAsRTFDAttachment:(NSFileWrapper *)wrapper
194 {
195     NSTextAttachment *attachment = [[NSTextAttachment alloc] initWithFileWrapper:wrapper];
196     
197     NSAttributedString *string = [NSAttributedString attributedStringWithAttachment:attachment];
198     [attachment release];
199     
200     NSData *RTFDData = [string RTFDFromRange:NSMakeRange(0, [string length]) documentAttributes:nil];
201     [self setData:RTFDData forType:NSRTFDPboardType];
202 }
203
204 - (void)_web_writeImage:(WebImageRenderer *)image 
205                     URL:(NSURL *)URL 
206                   title:(NSString *)title
207                 archive:(WebArchive *)archive
208                   types:(NSArray *)types
209 {
210     ASSERT(image);
211     ASSERT(URL);
212
213     [self _web_writeURL:URL andTitle:title types:types];
214     
215     if ([types containsObject:NSTIFFPboardType]) {
216         [self setData:[image TIFFRepresentation] forType:NSTIFFPboardType];
217     }
218     
219     if (archive) {
220         if ([types containsObject:NSRTFDPboardType]) {
221             // This image data is either the only subresource of an archive (HTML image case)
222             // or the main resource (standalone image case).
223             NSArray *subresources = [archive subresources];
224             WebResource *resource = [subresources count] > 0 ? [subresources objectAtIndex:0] : [archive mainResource];
225             ASSERT(resource != nil);
226             
227             ASSERT([[[WebImageRendererFactory sharedFactory] supportedMIMETypes] containsObject:[resource MIMEType]]);
228             [self _web_writeFileWrapperAsRTFDAttachment:[resource _fileWrapperRepresentation]];
229         }
230         if ([types containsObject:WebArchivePboardType]) {
231             [self setData:[archive data] forType:WebArchivePboardType];
232         }
233     } else {
234         // We should not have declared types that we aren't going to write (4031826).
235         ASSERT(![types containsObject:NSRTFDPboardType]);
236         ASSERT(![types containsObject:WebArchivePboardType]);
237     }
238 }
239
240 - (id)_web_declareAndWriteDragImage:(WebImageRenderer *)image 
241                                 URL:(NSURL *)URL 
242                               title:(NSString *)title
243                             archive:(WebArchive *)archive
244                              source:(id)source
245 {
246     ASSERT(self == [NSPasteboard pasteboardWithName:NSDragPboard]);
247     NSMutableArray *types = [[NSMutableArray alloc] initWithObjects:NSFilesPromisePboardType, nil];
248     [types addObjectsFromArray:[NSPasteboard _web_writableTypesForImageIncludingArchive:(archive != nil)]];
249     [self declareTypes:types owner:source];    
250     [self _web_writeImage:image URL:URL title:title archive:archive types:types];
251     [types release];
252     
253     NSString *extension = WKGetPreferredExtensionForMIMEType([image MIMEType]);
254     if (extension == nil) {
255         extension = @"";
256     }
257     NSArray *extensions = [NSArray arrayWithObject:extension];
258     
259 #ifdef OMIT_TIGER_FEATURES
260     id dragSource = [[NSFilePromiseDragSource alloc] initWithSource:source];
261     [dragSource setTypes:extensions onPasteboard:self];
262     return dragSource;
263 #else
264     [self setPropertyList:extensions forType:NSFilesPromisePboardType];
265     return source;
266 #endif
267 }
268
269 @end