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