91
static String MIMETypeFromCocoaType(NSString *type)
96
static String utiTypeFromCocoaType(NSString *type)
98
RetainPtr<CFStringRef> utiType(AdoptCF, UTTypeCreatePreferredIdentifierForTag(kUTTagClassNSPboardType, (CFStringRef)type, NULL));
100
RetainPtr<CFStringRef> mimeType(AdoptCF, UTTypeCopyPreferredTagWithClass(utiType.get(), kUTTagClassMIMEType));
102
return String(mimeType.get());
107
static void addHTMLClipboardTypesForCocoaType(HashSet<String>& resultTypes, NSString *cocoaType, NSPasteboard *pasteboard)
93
109
// UTI may not do these right, so make sure we get the right, predictable result
94
if ([type isEqualToString:NSStringPboardType])
96
if ([type isEqualToString:NSURLPboardType] || [type isEqualToString:NSFilenamesPboardType])
97
return "text/uri-list";
99
// Now try the general UTI mechanism
100
CFStringRef UTIType = UTTypeCreatePreferredIdentifierForTag(kUTTagClassNSPboardType, (CFStringRef)type, NULL);
102
CFStringRef mimeType = UTTypeCopyPreferredTagWithClass(UTIType, kUTTagClassMIMEType);
105
String result = mimeType;
110
if ([cocoaType isEqualToString:NSStringPboardType])
111
resultTypes.add("text/plain");
112
else if ([cocoaType isEqualToString:NSURLPboardType])
113
resultTypes.add("text/uri-list");
114
else if ([cocoaType isEqualToString:NSFilenamesPboardType]) {
115
// If file list is empty, add nothing.
116
// Note that there is a chance that the file list count could have changed since we grabbed the types array.
117
// However, this is not really an issue for us doing a sanity check here.
118
NSArray *fileList = [pasteboard propertyListForType:NSFilenamesPboardType];
119
if ([fileList count]) {
120
// It is unknown if NSFilenamesPboardType always implies NSURLPboardType in Cocoa,
121
// but NSFilenamesPboardType should imply both 'text/uri-list' and 'Files'
122
resultTypes.add("text/uri-list");
123
resultTypes.add("Files");
125
} else if (String utiType = utiTypeFromCocoaType(cocoaType))
126
resultTypes.add(utiType);
128
// No mapping, just pass the whole string though
129
resultTypes.add(cocoaType);
111
// No mapping, just pass the whole string though
115
133
void ClipboardMac::clearData(const String& type)
135
152
[m_pasteboard.get() declareTypes:[NSArray array] owner:nil];
155
static NSArray *absoluteURLsFromPasteboardFilenames(NSPasteboard* pasteboard, bool onlyFirstURL = false)
157
NSArray *fileList = [pasteboard propertyListForType:NSFilenamesPboardType];
159
// FIXME: Why does this code need to guard against bad values on the pasteboard?
160
ASSERT(!fileList || [fileList isKindOfClass:[NSArray class]]);
161
if (!fileList || ![fileList isKindOfClass:[NSArray class]] || ![fileList count])
164
NSUInteger count = onlyFirstURL ? 1 : [fileList count];
165
NSMutableArray *urls = [NSMutableArray array];
166
for (NSUInteger i = 0; i < count; i++) {
167
NSString *string = [fileList objectAtIndex:i];
169
ASSERT([string isKindOfClass:[NSString class]]); // Added to understand why this if code is here
170
if (![string isKindOfClass:[NSString class]])
171
return nil; // Non-string object in the list, bail out! FIXME: When can this happen?
173
NSURL *url = [NSURL fileURLWithPath:string];
174
[urls addObject:[url absoluteString]];
179
static NSArray *absoluteURLsFromPasteboard(NSPasteboard* pasteboard, bool onlyFirstURL = false)
181
// NOTE: We must always check [availableTypes containsObject:] before accessing pasteboard data
182
// or CoreFoundation will printf when there is not data of the corresponding type.
183
NSArray *availableTypes = [pasteboard types];
185
// Try NSFilenamesPboardType because it contains a list
186
if ([availableTypes containsObject:NSFilenamesPboardType]) {
187
if (NSArray* absoluteURLs = absoluteURLsFromPasteboardFilenames(pasteboard, onlyFirstURL))
191
// Fallback to NSURLPboardType (which is a single URL)
192
if ([availableTypes containsObject:NSURLPboardType]) {
193
if (NSURL *url = [NSURL URLFromPasteboard:pasteboard])
194
return [NSArray arrayWithObject:[url absoluteString]];
197
// No file paths on the pasteboard, return nil
138
201
String ClipboardMac::getData(const String& type, bool& success) const
141
204
if (policy() != ClipboardReadable)
144
NSString *cocoaType = cocoaTypeFromMIMEType(type);
207
NSString *cocoaType = cocoaTypeFromHTMLClipboardType(type);
145
208
NSString *cocoaValue = nil;
146
NSArray *availableTypes = [m_pasteboard.get() types];
148
// Fetch the data in different ways for the different Cocoa types
210
// Grab the value off the pasteboard corresponding to the cocoaType
150
211
if ([cocoaType isEqualToString:NSURLPboardType]) {
151
// When both URL and filenames are present, filenames is superior since it can contain a list.
152
// must check this or we get a printf from CF when there's no data of this type
153
if ([availableTypes containsObject:NSFilenamesPboardType]) {
154
NSArray *fileList = [m_pasteboard.get() propertyListForType:NSFilenamesPboardType];
155
if (fileList && [fileList isKindOfClass:[NSArray class]]) {
156
unsigned count = [fileList count];
158
if (type != "text/uri-list")
160
NSMutableString *urls = [NSMutableString string];
162
for (i = 0; i < count; i++) {
164
[urls appendString:@"\n"];
166
NSString *string = [fileList objectAtIndex:i];
167
if (![string isKindOfClass:[NSString class]])
169
NSURL *url = [NSURL fileURLWithPath:string];
170
[urls appendString:[url absoluteString]];
178
// must check this or we get a printf from CF when there's no data of this type
179
if ([availableTypes containsObject:NSURLPboardType]) {
180
NSURL *url = [NSURL URLFromPasteboard:m_pasteboard.get()];
182
cocoaValue = [url absoluteString];
186
} else if (cocoaType) {
212
// "URL" and "text/url-list" both map to NSURLPboardType in cocoaTypeFromHTMLClipboardType(), "URL" only wants the first URL
213
bool onlyFirstURL = (type == "URL");
214
NSArray *absoluteURLs = absoluteURLsFromPasteboard(m_pasteboard.get(), onlyFirstURL);
215
cocoaValue = [absoluteURLs componentsJoinedByString:@"\n"];
216
} else if ([cocoaType isEqualToString:NSStringPboardType]) {
217
cocoaValue = [[m_pasteboard.get() stringForType:cocoaType] precomposedStringWithCanonicalMapping];
218
} else if (cocoaType)
187
219
cocoaValue = [m_pasteboard.get() stringForType:cocoaType];
190
221
// Enforce changeCount ourselves for security. We check after reading instead of before to be
191
222
// sure it doesn't change between our testing the change count and accessing the data.
243
274
return HashSet<String>();
245
276
HashSet<String> result;
247
unsigned count = [types count];
249
for (i = 0; i < count; i++) {
250
NSString *pbType = [types objectAtIndex:i];
251
if ([pbType isEqualToString:@"NeXT plain ascii pasteboard type"])
252
continue; // skip this ancient type that gets auto-supplied by some system conversion
277
NSUInteger count = [types count];
278
// FIXME: This loop could be split into two stages. One which adds all the HTML5 specified types
279
// and a second which adds all the extra types from the cocoa clipboard (which is Mac-only behavior).
280
for (NSUInteger i = 0; i < count; i++) {
281
NSString *pbType = [types objectAtIndex:i];
282
if ([pbType isEqualToString:@"NeXT plain ascii pasteboard type"])
283
continue; // skip this ancient type that gets auto-supplied by some system conversion
254
String str = MIMETypeFromCocoaType(pbType);
255
if (!result.contains(str))
285
addHTMLClipboardTypesForCocoaType(result, pbType, m_pasteboard.get());
291
// FIXME: We could cache the computed fileList if necessary
292
// Currently each access gets a new copy, setData() modifications to the
293
// clipboard are not reflected in any FileList objects the page has accessed and stored
294
PassRefPtr<FileList> ClipboardMac::files() const
296
if (policy() != ClipboardReadable)
297
return FileList::create();
299
NSArray *absoluteURLs = absoluteURLsFromPasteboardFilenames(m_pasteboard.get());
300
NSUInteger count = [absoluteURLs count];
302
RefPtr<FileList> fileList = FileList::create();
303
for (NSUInteger x = 0; x < count; x++) {
304
NSURL *absoluteURL = [NSURL URLWithString:[absoluteURLs objectAtIndex:x]];
305
ASSERT([absoluteURL isFileURL]);
306
fileList->append(File::create([absoluteURL path]));
308
return fileList.release(); // We will always return a FileList, sometimes empty
262
311
// The rest of these getters don't really have any impact on security, so for now make no checks
264
313
void ClipboardMac::setDragImage(CachedImage* img, const IntPoint &loc)
319
368
Pasteboard::writeURL(m_pasteboard.get(), nil, url, title, frame);
371
#if ENABLE(DRAG_SUPPORT)
322
372
void ClipboardMac::declareAndWriteDragImage(Element* element, const KURL& url, const String& title, Frame* frame)
325
375
if (Page* page = frame->page())
326
page->dragController()->client()->declareAndWriteDragImage(m_pasteboard.get(), [DOMElement _wrapElement:element], url, title, frame);
376
page->dragController()->client()->declareAndWriteDragImage(m_pasteboard.get(), kit(element), url, title, frame);
378
#endif // ENABLE(DRAG_SUPPORT)
329
380
DragImageRef ClipboardMac::createDragImage(IntPoint& loc) const