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