Home | History | Annotate | Download | only in mac
      1 /*
      2  * Copyright (C) 2006 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  * 1. Redistributions of source code must retain the above copyright
      8  *    notice, this list of conditions and the following disclaimer.
      9  * 2. Redistributions in binary form must reproduce the above copyright
     10  *    notice, this list of conditions and the following disclaimer in the
     11  *    documentation and/or other materials provided with the distribution.
     12  *
     13  * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
     14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
     17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
     18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
     19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
     20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
     21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     24  */
     25 
     26 #import "config.h"
     27 #import "Pasteboard.h"
     28 
     29 #import "CachedResource.h"
     30 #import "DOMRangeInternal.h"
     31 #import "Document.h"
     32 #import "DocumentFragment.h"
     33 #import "DocumentLoader.h"
     34 #import "Editor.h"
     35 #import "EditorClient.h"
     36 #import "Frame.h"
     37 #import "FrameView.h"
     38 #import "FrameLoaderClient.h"
     39 #import "HitTestResult.h"
     40 #import "HTMLAnchorElement.h"
     41 #import "HTMLConverter.h"
     42 #import "htmlediting.h"
     43 #import "HTMLNames.h"
     44 #import "Image.h"
     45 #import "KURL.h"
     46 #import "LegacyWebArchive.h"
     47 #import "LoaderNSURLExtras.h"
     48 #import "MIMETypeRegistry.h"
     49 #import "Page.h"
     50 #import "RenderImage.h"
     51 #import "Text.h"
     52 #import "WebCoreNSStringExtras.h"
     53 #import "WebNSAttributedStringExtras.h"
     54 #import "markup.h"
     55 #import <wtf/StdLibExtras.h>
     56 #import <wtf/RetainPtr.h>
     57 #import <wtf/UnusedParam.h>
     58 #import <wtf/unicode/CharacterNames.h>
     59 
     60 @interface NSAttributedString (AppKitSecretsIKnowAbout)
     61 - (id)_initWithDOMRange:(DOMRange *)domRange;
     62 @end
     63 namespace WebCore {
     64 
     65 // FIXME: It's not great to have these both here and in WebKit.
     66 NSString *WebArchivePboardType = @"Apple Web Archive pasteboard type";
     67 NSString *WebSmartPastePboardType = @"NeXT smart paste pasteboard type";
     68 NSString *WebURLNamePboardType = @"public.url-name";
     69 NSString *WebURLPboardType = @"public.url";
     70 NSString *WebURLsWithTitlesPboardType = @"WebURLsWithTitlesPboardType";
     71 
     72 #ifndef BUILDING_ON_TIGER
     73 static NSArray* selectionPasteboardTypes(bool canSmartCopyOrDelete, bool selectionContainsAttachments)
     74 {
     75     if (selectionContainsAttachments) {
     76         if (canSmartCopyOrDelete)
     77             return [NSArray arrayWithObjects:WebSmartPastePboardType, WebArchivePboardType, NSRTFDPboardType, NSRTFPboardType, NSStringPboardType, nil];
     78         else
     79             return [NSArray arrayWithObjects:WebArchivePboardType, NSRTFDPboardType, NSRTFPboardType, NSStringPboardType, nil];
     80     } else { // Don't write RTFD to the pasteboard when the copied attributed string has no attachments.
     81         if (canSmartCopyOrDelete)
     82             return [NSArray arrayWithObjects:WebSmartPastePboardType, WebArchivePboardType, NSRTFPboardType, NSStringPboardType, nil];
     83         else
     84             return [NSArray arrayWithObjects:WebArchivePboardType, NSRTFPboardType, NSStringPboardType, nil];
     85     }
     86 }
     87 #endif
     88 
     89 static NSArray* writableTypesForURL()
     90 {
     91     DEFINE_STATIC_LOCAL(RetainPtr<NSArray>, types, ([[NSArray alloc] initWithObjects:
     92             WebURLsWithTitlesPboardType,
     93             NSURLPboardType,
     94             WebURLPboardType,
     95             WebURLNamePboardType,
     96             NSStringPboardType,
     97             nil]));
     98     return types.get();
     99 }
    100 
    101 static inline NSArray* createWritableTypesForImage()
    102 {
    103     NSMutableArray *types = [[NSMutableArray alloc] initWithObjects:NSTIFFPboardType, nil];
    104     [types addObjectsFromArray:writableTypesForURL()];
    105     [types addObject:NSRTFDPboardType];
    106     return types;
    107 }
    108 
    109 static NSArray* writableTypesForImage()
    110 {
    111     DEFINE_STATIC_LOCAL(RetainPtr<NSArray>, types, (createWritableTypesForImage()));
    112     return types.get();
    113 }
    114 
    115 Pasteboard* Pasteboard::generalPasteboard()
    116 {
    117     static Pasteboard* pasteboard = new Pasteboard([NSPasteboard generalPasteboard]);
    118     return pasteboard;
    119 }
    120 
    121 Pasteboard::Pasteboard(NSPasteboard* pboard)
    122     : m_pasteboard(pboard)
    123 {
    124 }
    125 
    126 void Pasteboard::clear()
    127 {
    128     [m_pasteboard.get() declareTypes:[NSArray array] owner:nil];
    129 }
    130 
    131 void Pasteboard::writeSelection(NSPasteboard* pasteboard, NSArray* pasteboardTypes, Range* selectedRange, bool canSmartCopyOrDelete, Frame* frame)
    132 {
    133     if (!WebArchivePboardType)
    134         Pasteboard::generalPasteboard(); // Initializes pasteboard types.
    135     ASSERT(selectedRange);
    136 
    137     // If the selection is at the beginning of content inside an anchor tag
    138     // we move the selection start to include the anchor.
    139     // This way the attributed string will contain the url attribute as well.
    140     // See <rdar://problem/9084267>.
    141     ExceptionCode ec;
    142     Node* commonAncestor = selectedRange->commonAncestorContainer(ec);
    143     ASSERT(commonAncestor);
    144     Node* enclosingAnchor = enclosingNodeWithTag(firstPositionInNode(commonAncestor), HTMLNames::aTag);
    145     if (enclosingAnchor && comparePositions(firstPositionInOrBeforeNode(selectedRange->startPosition().anchorNode()), selectedRange->startPosition()) >= 0)
    146         selectedRange->setStart(enclosingAnchor, 0, ec);
    147 
    148     // Using different API for WebKit and WebKit2.
    149     NSAttributedString *attributedString = nil;
    150     if (frame->view()->platformWidget())
    151         attributedString = [[[NSAttributedString alloc] _initWithDOMRange:kit(selectedRange)] autorelease];
    152 #if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD)
    153     else {
    154         // In WebKit2 we are using a different way to create the NSAttributedString from the DOMrange that doesn't require access to the WebView.
    155         RetainPtr<WebHTMLConverter> converter = [[WebHTMLConverter alloc] initWithDOMRange:kit(selectedRange)];
    156         if (converter)
    157             attributedString = [converter.get() attributedString];
    158     }
    159 #endif
    160 
    161 #ifdef BUILDING_ON_TIGER
    162     // 4930197: Mail overrides [WebHTMLView pasteboardTypesForSelection] in order to add another type to the pasteboard
    163     // after WebKit does.  On Tiger we must call this function so that Mail code will be executed, meaning that
    164     // we can't call WebCore::Pasteboard's method for setting types.
    165     UNUSED_PARAM(canSmartCopyOrDelete);
    166 
    167     NSArray *types = pasteboardTypes ? pasteboardTypes : frame->editor()->client()->pasteboardTypesForSelection(frame);
    168     // Don't write RTFD to the pasteboard when the copied attributed string has no attachments.
    169     NSMutableArray *mutableTypes = nil;
    170     if (![attributedString containsAttachments]) {
    171         mutableTypes = [[types mutableCopy] autorelease];
    172         [mutableTypes removeObject:NSRTFDPboardType];
    173         types = mutableTypes;
    174     }
    175     [pasteboard declareTypes:types owner:nil];
    176 #else
    177     NSArray *types = pasteboardTypes ? pasteboardTypes : selectionPasteboardTypes(canSmartCopyOrDelete, [attributedString containsAttachments]);
    178     [pasteboard declareTypes:types owner:nil];
    179     frame->editor()->client()->didSetSelectionTypesForPasteboard();
    180 #endif
    181 
    182     // Put HTML on the pasteboard.
    183     if ([types containsObject:WebArchivePboardType]) {
    184         RefPtr<LegacyWebArchive> archive = LegacyWebArchive::createFromSelection(frame);
    185         RetainPtr<CFDataRef> data = archive ? archive->rawDataRepresentation() : 0;
    186         [pasteboard setData:(NSData *)data.get() forType:WebArchivePboardType];
    187     }
    188 
    189     // Put the attributed string on the pasteboard (RTF/RTFD format).
    190     if ([types containsObject:NSRTFDPboardType]) {
    191         NSData *RTFDData = [attributedString RTFDFromRange:NSMakeRange(0, [attributedString length]) documentAttributes:nil];
    192         [pasteboard setData:RTFDData forType:NSRTFDPboardType];
    193     }
    194     if ([types containsObject:NSRTFPboardType]) {
    195         if ([attributedString containsAttachments])
    196             attributedString = attributedStringByStrippingAttachmentCharacters(attributedString);
    197         NSData *RTFData = [attributedString RTFFromRange:NSMakeRange(0, [attributedString length]) documentAttributes:nil];
    198         [pasteboard setData:RTFData forType:NSRTFPboardType];
    199     }
    200 
    201     // Put plain string on the pasteboard.
    202     if ([types containsObject:NSStringPboardType]) {
    203         // Map &nbsp; to a plain old space because this is better for source code, other browsers do it,
    204         // and because HTML forces you to do this any time you want two spaces in a row.
    205         String text = frame->editor()->selectedText();
    206         NSMutableString *s = [[[(NSString*)text copy] autorelease] mutableCopy];
    207 
    208         NSString *NonBreakingSpaceString = [NSString stringWithCharacters:&noBreakSpace length:1];
    209         [s replaceOccurrencesOfString:NonBreakingSpaceString withString:@" " options:0 range:NSMakeRange(0, [s length])];
    210         [pasteboard setString:s forType:NSStringPboardType];
    211         [s release];
    212     }
    213 
    214     if ([types containsObject:WebSmartPastePboardType]) {
    215         [pasteboard setData:nil forType:WebSmartPastePboardType];
    216     }
    217 }
    218 
    219 void Pasteboard::writePlainText(NSPasteboard* pasteboard, const String& text)
    220 {
    221     NSArray *types = [NSArray arrayWithObject:NSStringPboardType];
    222     [pasteboard declareTypes:types owner:nil];
    223 
    224     [pasteboard setString:text forType:NSStringPboardType];
    225 }
    226 
    227 void Pasteboard::writeSelection(Range* selectedRange, bool canSmartCopyOrDelete, Frame* frame)
    228 {
    229     Pasteboard::writeSelection(m_pasteboard.get(), 0, selectedRange, canSmartCopyOrDelete, frame);
    230 }
    231 
    232 void Pasteboard::writePlainText(const String& text)
    233 {
    234     if (!WebArchivePboardType)
    235         Pasteboard::generalPasteboard(); // Initializes pasteboard types.
    236 
    237     NSArray *types = [NSArray arrayWithObject:NSStringPboardType];
    238     NSPasteboard *pasteboard = m_pasteboard.get();
    239     [pasteboard declareTypes:types owner:nil];
    240 
    241     [pasteboard setString:text forType:NSStringPboardType];
    242 }
    243 
    244 void Pasteboard::writeURL(NSPasteboard* pasteboard, NSArray* types, const KURL& url, const String& titleStr, Frame* frame)
    245 {
    246     if (!WebArchivePboardType)
    247         Pasteboard::generalPasteboard(); // Initializes pasteboard types.
    248 
    249     if (!types) {
    250         types = writableTypesForURL();
    251         [pasteboard declareTypes:types owner:nil];
    252     }
    253 
    254     ASSERT(!url.isEmpty());
    255 
    256     NSURL *cocoaURL = url;
    257     NSString *userVisibleString = frame->editor()->client()->userVisibleString(cocoaURL);
    258 
    259     NSString *title = (NSString*)titleStr;
    260     if ([title length] == 0) {
    261         title = [[cocoaURL path] lastPathComponent];
    262         if ([title length] == 0)
    263             title = userVisibleString;
    264     }
    265 
    266     if ([types containsObject:WebURLsWithTitlesPboardType])
    267         [pasteboard setPropertyList:[NSArray arrayWithObjects:[NSArray arrayWithObject:userVisibleString],
    268                                      [NSArray arrayWithObject:(NSString*)titleStr.stripWhiteSpace()],
    269                                      nil]
    270                             forType:WebURLsWithTitlesPboardType];
    271     if ([types containsObject:NSURLPboardType])
    272         [cocoaURL writeToPasteboard:pasteboard];
    273     if ([types containsObject:WebURLPboardType])
    274         [pasteboard setString:userVisibleString forType:WebURLPboardType];
    275     if ([types containsObject:WebURLNamePboardType])
    276         [pasteboard setString:title forType:WebURLNamePboardType];
    277     if ([types containsObject:NSStringPboardType])
    278         [pasteboard setString:userVisibleString forType:NSStringPboardType];
    279 }
    280 
    281 void Pasteboard::writeURL(const KURL& url, const String& titleStr, Frame* frame)
    282 {
    283     Pasteboard::writeURL(m_pasteboard.get(), nil, url, titleStr, frame);
    284 }
    285 
    286 static NSFileWrapper* fileWrapperForImage(CachedResource* resource, NSURL *url)
    287 {
    288     SharedBuffer* coreData = resource->data();
    289     NSData *data = [[[NSData alloc] initWithBytes:coreData->data() length:coreData->size()] autorelease];
    290     NSFileWrapper *wrapper = [[[NSFileWrapper alloc] initRegularFileWithContents:data] autorelease];
    291     String coreMIMEType = resource->response().mimeType();
    292     NSString *MIMEType = nil;
    293     if (!coreMIMEType.isNull())
    294         MIMEType = coreMIMEType;
    295     [wrapper setPreferredFilename:suggestedFilenameWithMIMEType(url, MIMEType)];
    296     return wrapper;
    297 }
    298 
    299 void Pasteboard::writeFileWrapperAsRTFDAttachment(NSFileWrapper* wrapper)
    300 {
    301     NSTextAttachment *attachment = [[NSTextAttachment alloc] initWithFileWrapper:wrapper];
    302 
    303     NSAttributedString *string = [NSAttributedString attributedStringWithAttachment:attachment];
    304     [attachment release];
    305 
    306     NSData *RTFDData = [string RTFDFromRange:NSMakeRange(0, [string length]) documentAttributes:nil];
    307     [m_pasteboard.get() setData:RTFDData forType:NSRTFDPboardType];
    308 }
    309 
    310 void Pasteboard::writeImage(Node* node, const KURL& url, const String& title)
    311 {
    312     ASSERT(node);
    313     Frame* frame = node->document()->frame();
    314 
    315     NSURL *cocoaURL = url;
    316     ASSERT(cocoaURL);
    317 
    318     ASSERT(node->renderer() && node->renderer()->isImage());
    319     RenderImage* renderer = toRenderImage(node->renderer());
    320     CachedImage* cachedImage = renderer->cachedImage();
    321     if (!cachedImage || cachedImage->errorOccurred())
    322         return;
    323 
    324     NSArray* types = writableTypesForImage();
    325     [m_pasteboard.get() declareTypes:types owner:nil];
    326     writeURL(m_pasteboard.get(), types, cocoaURL, nsStringNilIfEmpty(title), frame);
    327 
    328     Image* image = cachedImage->image();
    329     ASSERT(image);
    330 
    331     [m_pasteboard.get() setData:[image->getNSImage() TIFFRepresentation] forType:NSTIFFPboardType];
    332 
    333     String MIMEType = cachedImage->response().mimeType();
    334     ASSERT(MIMETypeRegistry::isSupportedImageResourceMIMEType(MIMEType));
    335 
    336     writeFileWrapperAsRTFDAttachment(fileWrapperForImage(cachedImage, cocoaURL));
    337 }
    338 
    339 bool Pasteboard::canSmartReplace()
    340 {
    341     return [[m_pasteboard.get() types] containsObject:WebSmartPastePboardType];
    342 }
    343 
    344 String Pasteboard::plainText(Frame* frame)
    345 {
    346     NSArray *types = [m_pasteboard.get() types];
    347 
    348     if ([types containsObject:NSStringPboardType])
    349         return [[m_pasteboard.get() stringForType:NSStringPboardType] precomposedStringWithCanonicalMapping];
    350 
    351     NSAttributedString *attributedString = nil;
    352     NSString *string;
    353 
    354     if ([types containsObject:NSRTFDPboardType])
    355         attributedString = [[NSAttributedString alloc] initWithRTFD:[m_pasteboard.get() dataForType:NSRTFDPboardType] documentAttributes:NULL];
    356     if (attributedString == nil && [types containsObject:NSRTFPboardType])
    357         attributedString = [[NSAttributedString alloc] initWithRTF:[m_pasteboard.get() dataForType:NSRTFPboardType] documentAttributes:NULL];
    358     if (attributedString != nil) {
    359         string = [[attributedString string] precomposedStringWithCanonicalMapping];
    360         [attributedString release];
    361         return string;
    362     }
    363 
    364     if ([types containsObject:NSFilenamesPboardType]) {
    365         string = [[[m_pasteboard.get() propertyListForType:NSFilenamesPboardType] componentsJoinedByString:@"\n"] precomposedStringWithCanonicalMapping];
    366         if (string != nil)
    367             return string;
    368     }
    369 
    370 
    371     if (NSURL *url = [NSURL URLFromPasteboard:m_pasteboard.get()]) {
    372         // FIXME: using the editorClient to call into webkit, for now, since
    373         // calling _web_userVisibleString from WebCore involves migrating a sizable web of
    374         // helper code that should either be done in a separate patch or figured out in another way.
    375         string = frame->editor()->client()->userVisibleString(url);
    376         if ([string length] > 0)
    377             return [string precomposedStringWithCanonicalMapping];
    378     }
    379 
    380 
    381     return String();
    382 }
    383 
    384 PassRefPtr<DocumentFragment> Pasteboard::documentFragmentWithImageResource(Frame* frame, PassRefPtr<ArchiveResource> resource)
    385 {
    386     if (DocumentLoader* loader = frame->loader()->documentLoader())
    387         loader->addArchiveResource(resource.get());
    388 
    389     RefPtr<Element> imageElement = frame->document()->createElement(HTMLNames::imgTag, false);
    390     if (!imageElement)
    391         return 0;
    392 
    393     NSURL *URL = resource->url();
    394     imageElement->setAttribute(HTMLNames::srcAttr, [URL isFileURL] ? [URL absoluteString] : resource->url());
    395     RefPtr<DocumentFragment> fragment = frame->document()->createDocumentFragment();
    396     if (fragment) {
    397         ExceptionCode ec;
    398         fragment->appendChild(imageElement, ec);
    399         return fragment.release();
    400     }
    401     return 0;
    402 }
    403 
    404 PassRefPtr<DocumentFragment> Pasteboard::documentFragmentWithRtf(Frame* frame, NSString* pboardType)
    405 {
    406     if (!frame || !frame->document() || !frame->document()->isHTMLDocument())
    407         return 0;
    408 
    409     NSAttributedString *string = nil;
    410     if (pboardType == NSRTFDPboardType)
    411         string = [[NSAttributedString alloc] initWithRTFD:[m_pasteboard.get() dataForType:NSRTFDPboardType] documentAttributes:NULL];
    412     if (string == nil)
    413         string = [[NSAttributedString alloc] initWithRTF:[m_pasteboard.get() dataForType:NSRTFPboardType] documentAttributes:NULL];
    414     if (string == nil)
    415         return nil;
    416 
    417     bool wasDeferringCallbacks = frame->page()->defersLoading();
    418     if (!wasDeferringCallbacks)
    419         frame->page()->setDefersLoading(true);
    420 
    421     Vector<RefPtr<ArchiveResource> > resources;
    422     RefPtr<DocumentFragment> fragment = frame->editor()->client()->documentFragmentFromAttributedString(string, resources);
    423 
    424     size_t size = resources.size();
    425     if (size) {
    426         DocumentLoader* loader = frame->loader()->documentLoader();
    427         for (size_t i = 0; i < size; ++i)
    428             loader->addArchiveResource(resources[i]);
    429     }
    430 
    431     if (!wasDeferringCallbacks)
    432         frame->page()->setDefersLoading(false);
    433 
    434     [string release];
    435     return fragment.release();
    436 }
    437 
    438 #define WebDataProtocolScheme @"webkit-fake-url"
    439 
    440 static NSURL* uniqueURLWithRelativePart(NSString *relativePart)
    441 {
    442     CFUUIDRef UUIDRef = CFUUIDCreate(kCFAllocatorDefault);
    443     NSString *UUIDString = (NSString *)CFUUIDCreateString(kCFAllocatorDefault, UUIDRef);
    444     CFRelease(UUIDRef);
    445     NSURL *URL = [NSURL URLWithString:[NSString stringWithFormat:@"%@://%@/%@", WebDataProtocolScheme, UUIDString, relativePart]];
    446     CFRelease(UUIDString);
    447 
    448     return URL;
    449 }
    450 
    451 NSURL *Pasteboard::getBestURL(Frame* frame)
    452 {
    453     NSArray *types = [m_pasteboard.get() types];
    454 
    455     // FIXME: using the editorClient to call into webkit, for now, since
    456     // calling webkit_canonicalize from WebCore involves migrating a sizable amount of
    457     // helper code that should either be done in a separate patch or figured out in another way.
    458 
    459     if ([types containsObject:NSURLPboardType]) {
    460         NSURL *URLFromPasteboard = [NSURL URLFromPasteboard:m_pasteboard.get()];
    461         NSString *scheme = [URLFromPasteboard scheme];
    462         if ([scheme isEqualToString:@"http"] || [scheme isEqualToString:@"https"]) {
    463             return frame->editor()->client()->canonicalizeURL(URLFromPasteboard);
    464         }
    465     }
    466 
    467     if ([types containsObject:NSStringPboardType]) {
    468         NSString *URLString = [m_pasteboard.get() stringForType:NSStringPboardType];
    469         NSURL *URL = frame->editor()->client()->canonicalizeURLString(URLString);
    470         if (URL)
    471             return URL;
    472     }
    473 
    474     if ([types containsObject:NSFilenamesPboardType]) {
    475         NSArray *files = [m_pasteboard.get() propertyListForType:NSFilenamesPboardType];
    476         // FIXME: Maybe it makes more sense to allow multiple files and only use the first one?
    477         if ([files count] == 1) {
    478             NSString *file = [files objectAtIndex:0];
    479             BOOL isDirectory;
    480             if ([[NSFileManager defaultManager] fileExistsAtPath:file isDirectory:&isDirectory] && isDirectory)
    481                 return nil;
    482             return frame->editor()->client()->canonicalizeURL([NSURL fileURLWithPath:file]);
    483         }
    484     }
    485 
    486     return nil;
    487 }
    488 
    489 String Pasteboard::asURL(Frame* frame)
    490 {
    491     return [getBestURL(frame) absoluteString];
    492 }
    493 
    494 PassRefPtr<DocumentFragment> Pasteboard::documentFragment(Frame* frame, PassRefPtr<Range> context, bool allowPlainText, bool& chosePlainText)
    495 {
    496     NSArray *types = [m_pasteboard.get() types];
    497     RefPtr<DocumentFragment> fragment;
    498     chosePlainText = false;
    499 
    500     if ([types containsObject:WebArchivePboardType]) {
    501         RefPtr<LegacyWebArchive> coreArchive = LegacyWebArchive::create(SharedBuffer::wrapNSData([m_pasteboard.get() dataForType:WebArchivePboardType]).get());
    502         if (coreArchive) {
    503             RefPtr<ArchiveResource> mainResource = coreArchive->mainResource();
    504             if (mainResource) {
    505                 NSString *MIMEType = mainResource->mimeType();
    506                 if (!frame || !frame->document())
    507                     return 0;
    508                 if (frame->loader()->client()->canShowMIMETypeAsHTML(MIMEType)) {
    509                     NSString *markupString = [[NSString alloc] initWithData:[mainResource->data()->createNSData() autorelease] encoding:NSUTF8StringEncoding];
    510                     // FIXME: seems poor form to do this as a side effect of getting a document fragment
    511                     if (DocumentLoader* loader = frame->loader()->documentLoader())
    512                         loader->addAllArchiveResources(coreArchive.get());
    513 
    514                     fragment = createFragmentFromMarkup(frame->document(), markupString, mainResource->url(), FragmentScriptingNotAllowed);
    515                     [markupString release];
    516                 } else if (MIMETypeRegistry::isSupportedImageMIMEType(MIMEType))
    517                    fragment = documentFragmentWithImageResource(frame, mainResource);
    518             }
    519         }
    520         if (fragment)
    521             return fragment.release();
    522     }
    523 
    524     if ([types containsObject:NSFilenamesPboardType]) {
    525         NSArray* paths = [m_pasteboard.get() propertyListForType:NSFilenamesPboardType];
    526         NSEnumerator* enumerator = [paths objectEnumerator];
    527         NSString* path;
    528         Vector< RefPtr<Node> > refNodesVector;
    529         Vector<Node*> nodesVector;
    530 
    531         while ((path = [enumerator nextObject]) != nil) {
    532             // Non-image file types; _web_userVisibleString is appropriate here because this will
    533             // be pasted as visible text.
    534             NSString *url = frame->editor()->client()->userVisibleString([NSURL fileURLWithPath:path]);
    535             RefPtr<Node> textNode = frame->document()->createTextNode(url);
    536             refNodesVector.append(textNode.get());
    537             nodesVector.append(textNode.get());
    538         }
    539         fragment = createFragmentFromNodes(frame->document(), nodesVector);
    540         if (fragment && fragment->firstChild())
    541             return fragment.release();
    542     }
    543 
    544     if ([types containsObject:NSHTMLPboardType]) {
    545         NSString *HTMLString = [m_pasteboard.get() stringForType:NSHTMLPboardType];
    546         // This is a hack to make Microsoft's HTML pasteboard data work. See 3778785.
    547         if ([HTMLString hasPrefix:@"Version:"]) {
    548             NSRange range = [HTMLString rangeOfString:@"<html" options:NSCaseInsensitiveSearch];
    549             if (range.location != NSNotFound) {
    550                 HTMLString = [HTMLString substringFromIndex:range.location];
    551             }
    552         }
    553         if ([HTMLString length] != 0 &&
    554             (fragment = createFragmentFromMarkup(frame->document(), HTMLString, "", FragmentScriptingNotAllowed)))
    555             return fragment.release();
    556     }
    557 
    558     if ([types containsObject:NSRTFDPboardType] &&
    559         (fragment = documentFragmentWithRtf(frame, NSRTFDPboardType)))
    560        return fragment.release();
    561 
    562     if ([types containsObject:NSRTFPboardType] &&
    563         (fragment = documentFragmentWithRtf(frame, NSRTFPboardType)))
    564         return fragment.release();
    565 
    566     if ([types containsObject:NSTIFFPboardType] &&
    567         (fragment = documentFragmentWithImageResource(frame, ArchiveResource::create(SharedBuffer::wrapNSData([[[m_pasteboard.get() dataForType:NSTIFFPboardType] copy] autorelease]), uniqueURLWithRelativePart(@"image.tiff"), "image/tiff", "", ""))))
    568         return fragment.release();
    569 
    570     if ([types containsObject:NSPDFPboardType] &&
    571         (fragment = documentFragmentWithImageResource(frame, ArchiveResource::create(SharedBuffer::wrapNSData([[[m_pasteboard.get() dataForType:NSPDFPboardType] copy] autorelease]), uniqueURLWithRelativePart(@"application.pdf"), "application/pdf", "", ""))))
    572         return fragment.release();
    573 
    574 #if defined(BUILDING_ON_TIGER) || defined(BUILDING_ON_LEOPARD)
    575     if ([types containsObject:NSPICTPboardType] &&
    576         (fragment = documentFragmentWithImageResource(frame, ArchiveResource::create(SharedBuffer::wrapNSData([[[m_pasteboard.get() dataForType:NSPICTPboardType] copy] autorelease]), uniqueURLWithRelativePart(@"image.pict"), "image/pict", "", ""))))
    577         return fragment.release();
    578 #endif
    579 
    580     // Only 10.5 and higher support setting and retrieving pasteboard types with UTIs, but we don't believe
    581     // that any applications on Tiger put types for which we only have a UTI, like PNG, on the pasteboard.
    582     if ([types containsObject:(NSString*)kUTTypePNG] &&
    583         (fragment = documentFragmentWithImageResource(frame, ArchiveResource::create(SharedBuffer::wrapNSData([[[m_pasteboard.get() dataForType:(NSString*)kUTTypePNG] copy] autorelease]), uniqueURLWithRelativePart(@"image.png"), "image/png", "", ""))))
    584         return fragment.release();
    585 
    586     if ([types containsObject:NSURLPboardType]) {
    587         NSURL *URL = [NSURL URLFromPasteboard:m_pasteboard.get()];
    588         Document* document = frame->document();
    589         ASSERT(document);
    590         if (!document)
    591             return 0;
    592         RefPtr<Element> anchor = document->createElement(HTMLNames::aTag, false);
    593         NSString *URLString = [URL absoluteString]; // Original data is ASCII-only, so there is no need to precompose.
    594         if ([URLString length] == 0)
    595             return nil;
    596         NSString *URLTitleString = [[m_pasteboard.get() stringForType:WebURLNamePboardType] precomposedStringWithCanonicalMapping];
    597         ExceptionCode ec;
    598         anchor->setAttribute(HTMLNames::hrefAttr, URLString);
    599         anchor->appendChild(document->createTextNode(URLTitleString), ec);
    600         fragment = document->createDocumentFragment();
    601         if (fragment) {
    602             fragment->appendChild(anchor, ec);
    603             return fragment.release();
    604         }
    605     }
    606 
    607     if (allowPlainText && [types containsObject:NSStringPboardType]) {
    608         chosePlainText = true;
    609         fragment = createFragmentFromText(context.get(), [[m_pasteboard.get() stringForType:NSStringPboardType] precomposedStringWithCanonicalMapping]);
    610         return fragment.release();
    611     }
    612 
    613     return 0;
    614 }
    615 
    616 }
    617