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