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 #import "WebNSPasteboardExtras.h" 30 31 #import "DOMElementInternal.h" 32 #import "WebArchive.h" 33 #import "WebFrameInternal.h" 34 #import "WebHTMLViewInternal.h" 35 #import "WebNSURLExtras.h" 36 #import "WebResourcePrivate.h" 37 #import "WebURLsWithTitles.h" 38 #import "WebViewPrivate.h" 39 #import <WebCore/Element.h> 40 #import <WebCore/Image.h> 41 #import <WebCore/MIMETypeRegistry.h> 42 #import <WebCore/RenderImage.h> 43 #import <WebKit/DOMExtensions.h> 44 #import <WebKit/DOMPrivate.h> 45 #import <WebKitSystemInterface.h> 46 #import <wtf/Assertions.h> 47 #import <wtf/RetainPtr.h> 48 #import <wtf/StdLibExtras.h> 49 50 using namespace WebCore; 51 52 NSString *WebURLPboardType = @"public.url"; 53 NSString *WebURLNamePboardType = @"public.url-name"; 54 55 @implementation NSPasteboard (WebExtras) 56 57 + (NSArray *)_web_writableTypesForURL 58 { 59 DEFINE_STATIC_LOCAL(RetainPtr<NSArray>, types, ([[NSArray alloc] initWithObjects: 60 WebURLsWithTitlesPboardType, 61 NSURLPboardType, 62 WebURLPboardType, 63 WebURLNamePboardType, 64 NSStringPboardType, 65 nil])); 66 return types.get(); 67 } 68 69 static inline NSArray *_createWritableTypesForImageWithoutArchive() 70 { 71 NSMutableArray *types = [[NSMutableArray alloc] initWithObjects:NSTIFFPboardType, nil]; 72 [types addObjectsFromArray:[NSPasteboard _web_writableTypesForURL]]; 73 return types; 74 } 75 76 static NSArray *_writableTypesForImageWithoutArchive (void) 77 { 78 DEFINE_STATIC_LOCAL(RetainPtr<NSArray>, types, (_createWritableTypesForImageWithoutArchive())); 79 return types.get(); 80 } 81 82 static inline NSArray *_createWritableTypesForImageWithArchive() 83 { 84 NSMutableArray *types = [_writableTypesForImageWithoutArchive() mutableCopy]; 85 [types addObject:NSRTFDPboardType]; 86 [types addObject:WebArchivePboardType]; 87 return types; 88 } 89 90 static NSArray *_writableTypesForImageWithArchive (void) 91 { 92 DEFINE_STATIC_LOCAL(RetainPtr<NSArray>, types, (_createWritableTypesForImageWithArchive())); 93 return types.get(); 94 } 95 96 + (NSArray *)_web_writableTypesForImageIncludingArchive:(BOOL)hasArchive 97 { 98 return hasArchive 99 ? _writableTypesForImageWithArchive() 100 : _writableTypesForImageWithoutArchive(); 101 } 102 103 + (NSArray *)_web_dragTypesForURL 104 { 105 return [NSArray arrayWithObjects: 106 WebURLsWithTitlesPboardType, 107 NSURLPboardType, 108 WebURLPboardType, 109 WebURLNamePboardType, 110 NSStringPboardType, 111 NSFilenamesPboardType, 112 nil]; 113 } 114 115 - (NSURL *)_web_bestURL 116 { 117 NSArray *types = [self types]; 118 119 if ([types containsObject:NSURLPboardType]) { 120 NSURL *URLFromPasteboard = [NSURL URLFromPasteboard:self]; 121 NSString *scheme = [URLFromPasteboard scheme]; 122 if ([scheme isEqualToString:@"http"] || [scheme isEqualToString:@"https"]) { 123 return [URLFromPasteboard _webkit_canonicalize]; 124 } 125 } 126 127 if ([types containsObject:NSStringPboardType]) { 128 NSString *URLString = [self stringForType:NSStringPboardType]; 129 if ([URLString _webkit_looksLikeAbsoluteURL]) { 130 NSURL *URL = [[NSURL _web_URLWithUserTypedString:URLString] _webkit_canonicalize]; 131 if (URL) { 132 return URL; 133 } 134 } 135 } 136 137 if ([types containsObject:NSFilenamesPboardType]) { 138 NSArray *files = [self propertyListForType:NSFilenamesPboardType]; 139 // FIXME: Maybe it makes more sense to allow multiple files and only use the first one? 140 if ([files count] == 1) { 141 NSString *file = [files objectAtIndex:0]; 142 // FIXME: We are filtering out directories because that's what the original code used to 143 // do. Without this check, if the URL points to a local directory, Safari will open the 144 // parent directory of the directory in Finder. This check should go away as soon as 145 // possible. 146 BOOL isDirectory; 147 if ([[NSFileManager defaultManager] fileExistsAtPath:file isDirectory:&isDirectory] && isDirectory) 148 return nil; 149 return [[NSURL fileURLWithPath:file] _webkit_canonicalize]; 150 } 151 } 152 153 return nil; 154 } 155 156 - (void)_web_writeURL:(NSURL *)URL andTitle:(NSString *)title types:(NSArray *)types 157 { 158 ASSERT(URL); 159 160 if ([title length] == 0) { 161 title = [[URL path] lastPathComponent]; 162 if ([title length] == 0) 163 title = [URL _web_userVisibleString]; 164 } 165 166 if ([types containsObject:NSURLPboardType]) 167 [URL writeToPasteboard:self]; 168 if ([types containsObject:WebURLPboardType]) 169 [self setString:[URL _web_originalDataAsString] forType:WebURLPboardType]; 170 if ([types containsObject:WebURLNamePboardType]) 171 [self setString:title forType:WebURLNamePboardType]; 172 if ([types containsObject:NSStringPboardType]) 173 [self setString:[URL _web_userVisibleString] forType:NSStringPboardType]; 174 if ([types containsObject:WebURLsWithTitlesPboardType]) 175 [WebURLsWithTitles writeURLs:[NSArray arrayWithObject:URL] andTitles:[NSArray arrayWithObject:title] toPasteboard:self]; 176 } 177 178 + (int)_web_setFindPasteboardString:(NSString *)string withOwner:(id)owner 179 { 180 NSPasteboard *findPasteboard = [NSPasteboard pasteboardWithName:NSFindPboard]; 181 [findPasteboard declareTypes:[NSArray arrayWithObject:NSStringPboardType] owner:owner]; 182 [findPasteboard setString:string forType:NSStringPboardType]; 183 return [findPasteboard changeCount]; 184 } 185 186 - (void)_web_writeFileWrapperAsRTFDAttachment:(NSFileWrapper *)wrapper 187 { 188 NSTextAttachment *attachment = [[NSTextAttachment alloc] initWithFileWrapper:wrapper]; 189 190 NSAttributedString *string = [NSAttributedString attributedStringWithAttachment:attachment]; 191 [attachment release]; 192 193 NSData *RTFDData = [string RTFDFromRange:NSMakeRange(0, [string length]) documentAttributes:nil]; 194 [self setData:RTFDData forType:NSRTFDPboardType]; 195 } 196 197 198 - (void)_web_writePromisedRTFDFromArchive:(WebArchive*)archive containsImage:(BOOL)containsImage 199 { 200 ASSERT(archive); 201 // This image data is either the only subresource of an archive (HTML image case) 202 // or the main resource (standalone image case). 203 NSArray *subresources = [archive subresources]; 204 WebResource *resource = [archive mainResource]; 205 if (containsImage && [subresources count] > 0 206 && MIMETypeRegistry::isSupportedImageResourceMIMEType([[subresources objectAtIndex:0] MIMEType])) 207 resource = (WebResource *)[subresources objectAtIndex:0]; 208 ASSERT(resource != nil); 209 210 ASSERT(!containsImage || MIMETypeRegistry::isSupportedImageResourceMIMEType([resource MIMEType])); 211 if (!containsImage || MIMETypeRegistry::isSupportedImageResourceMIMEType([resource MIMEType])) 212 [self _web_writeFileWrapperAsRTFDAttachment:[resource _fileWrapperRepresentation]]; 213 214 } 215 216 static CachedImage* imageFromElement(DOMElement *domElement) 217 { 218 Element* element = core(domElement); 219 if (!element) 220 return 0; 221 222 RenderObject* renderer = element->renderer(); 223 RenderImage* imageRenderer = toRenderImage(renderer); 224 if (!imageRenderer->cachedImage() || imageRenderer->cachedImage()->errorOccurred()) 225 return 0; 226 return imageRenderer->cachedImage(); 227 } 228 229 - (void)_web_writeImage:(NSImage *)image 230 element:(DOMElement *)element 231 URL:(NSURL *)URL 232 title:(NSString *)title 233 archive:(WebArchive *)archive 234 types:(NSArray *)types 235 source:(WebHTMLView *)source 236 { 237 ASSERT(image || element); 238 ASSERT(URL); 239 240 [self _web_writeURL:URL andTitle:title types:types]; 241 242 if ([types containsObject:NSTIFFPboardType]) { 243 if (image) 244 [self setData:[image TIFFRepresentation] forType:NSTIFFPboardType]; 245 else if (source && element) 246 [source setPromisedDragTIFFDataSource:imageFromElement(element)]; 247 else if (element) 248 [self setData:[element _imageTIFFRepresentation] forType:NSTIFFPboardType]; 249 } 250 251 if (archive) 252 if ([types containsObject:WebArchivePboardType]) 253 [self setData:[archive data] forType:WebArchivePboardType]; 254 else { 255 // We should not have declared types that we aren't going to write (4031826). 256 ASSERT(![types containsObject:NSRTFDPboardType]); 257 ASSERT(![types containsObject:WebArchivePboardType]); 258 } 259 } 260 261 - (id)_web_declareAndWriteDragImageForElement:(DOMElement *)element 262 URL:(NSURL *)URL 263 title:(NSString *)title 264 archive:(WebArchive *)archive 265 source:(WebHTMLView *)source 266 { 267 ASSERT(self == [NSPasteboard pasteboardWithName:NSDragPboard]); 268 269 NSString *extension = @""; 270 if (RenderObject* renderer = core(element)->renderer()) { 271 if (renderer->isImage()) { 272 if (CachedImage* image = toRenderImage(renderer)->cachedImage()) { 273 extension = image->image()->filenameExtension(); 274 if (![extension length]) 275 return 0; 276 } 277 } 278 } 279 280 NSMutableArray *types = [[NSMutableArray alloc] initWithObjects:NSFilesPromisePboardType, nil]; 281 [types addObjectsFromArray:[NSPasteboard _web_writableTypesForImageIncludingArchive:(archive != nil)]]; 282 [self declareTypes:types owner:source]; 283 [self _web_writeImage:nil element:element URL:URL title:title archive:archive types:types source:source]; 284 [types release]; 285 286 NSArray *extensions = [[NSArray alloc] initWithObjects:extension, nil]; 287 [self setPropertyList:extensions forType:NSFilesPromisePboardType]; 288 [extensions release]; 289 290 return source; 291 } 292 293 @end 294