Home | History | Annotate | Download | only in Misc
      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