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