widget/cocoa/nsClipboard.mm

changeset 0
6474c204b198
equal deleted inserted replaced
-1:000000000000 0:1d87df1ef5df
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5
6 #ifdef MOZ_LOGGING
7 #define FORCE_PR_LOG
8 #endif
9 #include "prlog.h"
10
11 #include "gfxPlatform.h"
12 #include "nsCOMPtr.h"
13 #include "nsClipboard.h"
14 #include "nsString.h"
15 #include "nsISupportsPrimitives.h"
16 #include "nsXPIDLString.h"
17 #include "nsPrimitiveHelpers.h"
18 #include "nsMemory.h"
19 #include "nsIFile.h"
20 #include "nsStringStream.h"
21 #include "nsDragService.h"
22 #include "nsEscape.h"
23 #include "nsPrintfCString.h"
24 #include "nsObjCExceptions.h"
25 #include "imgIContainer.h"
26 #include "nsCocoaUtils.h"
27
28 using mozilla::gfx::DataSourceSurface;
29 using mozilla::gfx::SourceSurface;
30 using mozilla::RefPtr;
31
32 // Screenshots use the (undocumented) png pasteboard type.
33 #define IMAGE_PASTEBOARD_TYPES NSTIFFPboardType, @"Apple PNG pasteboard type", nil
34
35 #ifdef PR_LOGGING
36 extern PRLogModuleInfo* sCocoaLog;
37 #endif
38
39 extern void EnsureLogInitialized();
40
41 nsClipboard::nsClipboard() : nsBaseClipboard()
42 {
43 mCachedClipboard = -1;
44 mChangeCount = 0;
45
46 EnsureLogInitialized();
47 }
48
49 nsClipboard::~nsClipboard()
50 {
51 }
52
53 // We separate this into its own function because after an @try, all local
54 // variables within that function get marked as volatile, and our C++ type
55 // system doesn't like volatile things.
56 static NSData*
57 GetDataFromPasteboard(NSPasteboard* aPasteboard, NSString* aType)
58 {
59 NSData *data = nil;
60 @try {
61 data = [aPasteboard dataForType:aType];
62 } @catch (NSException* e) {
63 NS_WARNING(nsPrintfCString("Exception raised while getting data from the pasteboard: \"%s - %s\"",
64 [[e name] UTF8String], [[e reason] UTF8String]).get());
65 }
66 return data;
67 }
68
69 NS_IMETHODIMP
70 nsClipboard::SetNativeClipboardData(int32_t aWhichClipboard)
71 {
72 NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
73
74 if ((aWhichClipboard != kGlobalClipboard && aWhichClipboard != kFindClipboard) || !mTransferable)
75 return NS_ERROR_FAILURE;
76
77 mIgnoreEmptyNotification = true;
78
79 NSDictionary* pasteboardOutputDict = PasteboardDictFromTransferable(mTransferable);
80 if (!pasteboardOutputDict)
81 return NS_ERROR_FAILURE;
82
83 unsigned int outputCount = [pasteboardOutputDict count];
84 NSArray* outputKeys = [pasteboardOutputDict allKeys];
85 NSPasteboard* cocoaPasteboard;
86 if (aWhichClipboard == kFindClipboard) {
87 cocoaPasteboard = [NSPasteboard pasteboardWithName:NSFindPboard];
88 [cocoaPasteboard declareTypes:[NSArray arrayWithObject:NSStringPboardType] owner:nil];
89 } else {
90 // Write everything else out to the general pasteboard.
91 cocoaPasteboard = [NSPasteboard generalPasteboard];
92 [cocoaPasteboard declareTypes:outputKeys owner:nil];
93 }
94
95 for (unsigned int i = 0; i < outputCount; i++) {
96 NSString* currentKey = [outputKeys objectAtIndex:i];
97 id currentValue = [pasteboardOutputDict valueForKey:currentKey];
98 if (aWhichClipboard == kFindClipboard) {
99 if (currentKey == NSStringPboardType)
100 [cocoaPasteboard setString:currentValue forType:currentKey];
101 } else {
102 if (currentKey == NSStringPboardType ||
103 currentKey == kCorePboardType_url ||
104 currentKey == kCorePboardType_urld ||
105 currentKey == kCorePboardType_urln) {
106 [cocoaPasteboard setString:currentValue forType:currentKey];
107 } else if (currentKey == NSHTMLPboardType) {
108 [cocoaPasteboard setString:(nsClipboard::WrapHtmlForSystemPasteboard(currentValue))
109 forType:currentKey];
110 } else {
111 [cocoaPasteboard setData:currentValue forType:currentKey];
112 }
113 }
114 }
115
116 mCachedClipboard = aWhichClipboard;
117 mChangeCount = [cocoaPasteboard changeCount];
118
119 mIgnoreEmptyNotification = false;
120
121 return NS_OK;
122
123 NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
124 }
125
126 nsresult
127 nsClipboard::TransferableFromPasteboard(nsITransferable *aTransferable, NSPasteboard *cocoaPasteboard)
128 {
129 NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
130
131 // get flavor list that includes all acceptable flavors (including ones obtained through conversion)
132 nsCOMPtr<nsISupportsArray> flavorList;
133 nsresult rv = aTransferable->FlavorsTransferableCanImport(getter_AddRefs(flavorList));
134 if (NS_FAILED(rv))
135 return NS_ERROR_FAILURE;
136
137 uint32_t flavorCount;
138 flavorList->Count(&flavorCount);
139
140 for (uint32_t i = 0; i < flavorCount; i++) {
141 nsCOMPtr<nsISupports> genericFlavor;
142 flavorList->GetElementAt(i, getter_AddRefs(genericFlavor));
143 nsCOMPtr<nsISupportsCString> currentFlavor(do_QueryInterface(genericFlavor));
144 if (!currentFlavor)
145 continue;
146
147 nsXPIDLCString flavorStr;
148 currentFlavor->ToString(getter_Copies(flavorStr)); // i has a flavr
149
150 // printf("looking for clipboard data of type %s\n", flavorStr.get());
151
152 NSString *pboardType = nil;
153 if (nsClipboard::IsStringType(flavorStr, &pboardType)) {
154 NSString* pString = [cocoaPasteboard stringForType:pboardType];
155 if (!pString)
156 continue;
157
158 NSData* stringData = [pString dataUsingEncoding:NSUnicodeStringEncoding];
159 unsigned int dataLength = [stringData length];
160 void* clipboardDataPtr = malloc(dataLength);
161 if (!clipboardDataPtr)
162 return NS_ERROR_OUT_OF_MEMORY;
163 [stringData getBytes:clipboardDataPtr];
164
165 // The DOM only wants LF, so convert from MacOS line endings to DOM line endings.
166 int32_t signedDataLength = dataLength;
167 nsLinebreakHelpers::ConvertPlatformToDOMLinebreaks(flavorStr, &clipboardDataPtr, &signedDataLength);
168 dataLength = signedDataLength;
169
170 // skip BOM (Byte Order Mark to distinguish little or big endian)
171 char16_t* clipboardDataPtrNoBOM = (char16_t*)clipboardDataPtr;
172 if ((dataLength > 2) &&
173 ((clipboardDataPtrNoBOM[0] == 0xFEFF) ||
174 (clipboardDataPtrNoBOM[0] == 0xFFFE))) {
175 dataLength -= sizeof(char16_t);
176 clipboardDataPtrNoBOM += 1;
177 }
178
179 nsCOMPtr<nsISupports> genericDataWrapper;
180 nsPrimitiveHelpers::CreatePrimitiveForData(flavorStr, clipboardDataPtrNoBOM, dataLength,
181 getter_AddRefs(genericDataWrapper));
182 aTransferable->SetTransferData(flavorStr, genericDataWrapper, dataLength);
183 free(clipboardDataPtr);
184 break;
185 }
186 else if (flavorStr.EqualsLiteral(kJPEGImageMime) ||
187 flavorStr.EqualsLiteral(kJPGImageMime) ||
188 flavorStr.EqualsLiteral(kPNGImageMime) ||
189 flavorStr.EqualsLiteral(kGIFImageMime)) {
190 // Figure out if there's data on the pasteboard we can grab (sanity check)
191 NSString *type = [cocoaPasteboard availableTypeFromArray:[NSArray arrayWithObjects:IMAGE_PASTEBOARD_TYPES]];
192 if (!type)
193 continue;
194
195 // Read data off the clipboard
196 NSData *pasteboardData = GetDataFromPasteboard(cocoaPasteboard, type);
197 if (!pasteboardData)
198 continue;
199
200 // Figure out what type we're converting to
201 CFStringRef outputType = NULL;
202 if (flavorStr.EqualsLiteral(kJPEGImageMime) ||
203 flavorStr.EqualsLiteral(kJPGImageMime))
204 outputType = CFSTR("public.jpeg");
205 else if (flavorStr.EqualsLiteral(kPNGImageMime))
206 outputType = CFSTR("public.png");
207 else if (flavorStr.EqualsLiteral(kGIFImageMime))
208 outputType = CFSTR("com.compuserve.gif");
209 else
210 continue;
211
212 // Use ImageIO to interpret the data on the clipboard and transcode.
213 // Note that ImageIO, like all CF APIs, allows NULLs to propagate freely
214 // and safely in most cases (like ObjC). A notable exception is CFRelease.
215 NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:
216 (NSNumber*)kCFBooleanTrue, kCGImageSourceShouldAllowFloat,
217 (type == NSTIFFPboardType ? @"public.tiff" : @"public.png"),
218 kCGImageSourceTypeIdentifierHint, nil];
219
220 CGImageSourceRef source = CGImageSourceCreateWithData((CFDataRef)pasteboardData,
221 (CFDictionaryRef)options);
222 NSMutableData *encodedData = [NSMutableData data];
223 CGImageDestinationRef dest = CGImageDestinationCreateWithData((CFMutableDataRef)encodedData,
224 outputType,
225 1, NULL);
226 CGImageDestinationAddImageFromSource(dest, source, 0, NULL);
227 bool successfullyConverted = CGImageDestinationFinalize(dest);
228
229 if (successfullyConverted) {
230 // Put the converted data in a form Gecko can understand
231 nsCOMPtr<nsIInputStream> byteStream;
232 NS_NewByteInputStream(getter_AddRefs(byteStream), (const char*)[encodedData bytes],
233 [encodedData length], NS_ASSIGNMENT_COPY);
234
235 aTransferable->SetTransferData(flavorStr, byteStream, sizeof(nsIInputStream*));
236 }
237
238 if (dest)
239 CFRelease(dest);
240 if (source)
241 CFRelease(source);
242
243 if (successfullyConverted)
244 break;
245 else
246 continue;
247 }
248 }
249
250 return NS_OK;
251
252 NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
253 }
254
255 NS_IMETHODIMP
256 nsClipboard::GetNativeClipboardData(nsITransferable* aTransferable, int32_t aWhichClipboard)
257 {
258 NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
259
260 if ((aWhichClipboard != kGlobalClipboard && aWhichClipboard != kFindClipboard) || !aTransferable)
261 return NS_ERROR_FAILURE;
262
263 NSPasteboard* cocoaPasteboard;
264 if (aWhichClipboard == kFindClipboard) {
265 cocoaPasteboard = [NSPasteboard pasteboardWithName:NSFindPboard];
266 } else {
267 cocoaPasteboard = [NSPasteboard generalPasteboard];
268 }
269 if (!cocoaPasteboard)
270 return NS_ERROR_FAILURE;
271
272 // get flavor list that includes all acceptable flavors (including ones obtained through conversion)
273 nsCOMPtr<nsISupportsArray> flavorList;
274 nsresult rv = aTransferable->FlavorsTransferableCanImport(getter_AddRefs(flavorList));
275 if (NS_FAILED(rv))
276 return NS_ERROR_FAILURE;
277
278 uint32_t flavorCount;
279 flavorList->Count(&flavorCount);
280
281 // If we were the last ones to put something on the pasteboard, then just use the cached
282 // transferable. Otherwise clear it because it isn't relevant any more.
283 if (mCachedClipboard == aWhichClipboard &&
284 mChangeCount == [cocoaPasteboard changeCount]) {
285 if (mTransferable) {
286 for (uint32_t i = 0; i < flavorCount; i++) {
287 nsCOMPtr<nsISupports> genericFlavor;
288 flavorList->GetElementAt(i, getter_AddRefs(genericFlavor));
289 nsCOMPtr<nsISupportsCString> currentFlavor(do_QueryInterface(genericFlavor));
290 if (!currentFlavor)
291 continue;
292
293 nsXPIDLCString flavorStr;
294 currentFlavor->ToString(getter_Copies(flavorStr));
295
296 nsCOMPtr<nsISupports> dataSupports;
297 uint32_t dataSize = 0;
298 rv = mTransferable->GetTransferData(flavorStr, getter_AddRefs(dataSupports), &dataSize);
299 if (NS_SUCCEEDED(rv)) {
300 aTransferable->SetTransferData(flavorStr, dataSupports, dataSize);
301 return NS_OK; // maybe try to fill in more types? Is there a point?
302 }
303 }
304 }
305 } else {
306 nsBaseClipboard::EmptyClipboard(aWhichClipboard);
307 }
308
309 // at this point we can't satisfy the request from cache data so let's look
310 // for things other people put on the system clipboard
311
312 return nsClipboard::TransferableFromPasteboard(aTransferable, cocoaPasteboard);
313
314 NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
315 }
316
317 // returns true if we have *any* of the passed in flavors available for pasting
318 NS_IMETHODIMP
319 nsClipboard::HasDataMatchingFlavors(const char** aFlavorList, uint32_t aLength,
320 int32_t aWhichClipboard, bool* outResult)
321 {
322 NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
323
324 *outResult = false;
325
326 if ((aWhichClipboard != kGlobalClipboard) || !aFlavorList)
327 return NS_OK;
328
329 // first see if we have data for this in our cached transferable
330 if (mTransferable) {
331 nsCOMPtr<nsISupportsArray> transferableFlavorList;
332 nsresult rv = mTransferable->FlavorsTransferableCanImport(getter_AddRefs(transferableFlavorList));
333 if (NS_SUCCEEDED(rv)) {
334 uint32_t transferableFlavorCount;
335 transferableFlavorList->Count(&transferableFlavorCount);
336 for (uint32_t j = 0; j < transferableFlavorCount; j++) {
337 nsCOMPtr<nsISupports> transferableFlavorSupports;
338 transferableFlavorList->GetElementAt(j, getter_AddRefs(transferableFlavorSupports));
339 nsCOMPtr<nsISupportsCString> currentTransferableFlavor(do_QueryInterface(transferableFlavorSupports));
340 if (!currentTransferableFlavor)
341 continue;
342 nsXPIDLCString transferableFlavorStr;
343 currentTransferableFlavor->ToString(getter_Copies(transferableFlavorStr));
344
345 for (uint32_t k = 0; k < aLength; k++) {
346 if (transferableFlavorStr.Equals(aFlavorList[k])) {
347 *outResult = true;
348 return NS_OK;
349 }
350 }
351 }
352 }
353 }
354
355 NSPasteboard* generalPBoard = [NSPasteboard generalPasteboard];
356
357 for (uint32_t i = 0; i < aLength; i++) {
358 nsDependentCString mimeType(aFlavorList[i]);
359 NSString *pboardType = nil;
360
361 if (nsClipboard::IsStringType(mimeType, &pboardType)) {
362 NSString* availableType = [generalPBoard availableTypeFromArray:[NSArray arrayWithObject:pboardType]];
363 if (availableType && [availableType isEqualToString:pboardType]) {
364 *outResult = true;
365 break;
366 }
367 } else if (!strcmp(aFlavorList[i], kJPEGImageMime) ||
368 !strcmp(aFlavorList[i], kJPGImageMime) ||
369 !strcmp(aFlavorList[i], kPNGImageMime) ||
370 !strcmp(aFlavorList[i], kGIFImageMime)) {
371 NSString* availableType = [generalPBoard availableTypeFromArray:
372 [NSArray arrayWithObjects:IMAGE_PASTEBOARD_TYPES]];
373 if (availableType) {
374 *outResult = true;
375 break;
376 }
377 }
378 }
379
380 return NS_OK;
381
382 NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
383 }
384
385 NS_IMETHODIMP
386 nsClipboard::SupportsFindClipboard(bool *_retval)
387 {
388 NS_ENSURE_ARG_POINTER(_retval);
389 *_retval = true;
390 return NS_OK;
391 }
392
393 // This function converts anything that other applications might understand into the system format
394 // and puts it into a dictionary which it returns.
395 // static
396 NSDictionary*
397 nsClipboard::PasteboardDictFromTransferable(nsITransferable* aTransferable)
398 {
399 NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL;
400
401 if (!aTransferable)
402 return nil;
403
404 NSMutableDictionary* pasteboardOutputDict = [NSMutableDictionary dictionary];
405
406 nsCOMPtr<nsISupportsArray> flavorList;
407 nsresult rv = aTransferable->FlavorsTransferableCanExport(getter_AddRefs(flavorList));
408 if (NS_FAILED(rv))
409 return nil;
410
411 uint32_t flavorCount;
412 flavorList->Count(&flavorCount);
413 for (uint32_t i = 0; i < flavorCount; i++) {
414 nsCOMPtr<nsISupports> genericFlavor;
415 flavorList->GetElementAt(i, getter_AddRefs(genericFlavor));
416 nsCOMPtr<nsISupportsCString> currentFlavor(do_QueryInterface(genericFlavor));
417 if (!currentFlavor)
418 continue;
419
420 nsXPIDLCString flavorStr;
421 currentFlavor->ToString(getter_Copies(flavorStr));
422
423 PR_LOG(sCocoaLog, PR_LOG_ALWAYS, ("writing out clipboard data of type %s (%d)\n", flavorStr.get(), i));
424
425 NSString *pboardType = nil;
426
427 if (nsClipboard::IsStringType(flavorStr, &pboardType)) {
428 void* data = nullptr;
429 uint32_t dataSize = 0;
430 nsCOMPtr<nsISupports> genericDataWrapper;
431 rv = aTransferable->GetTransferData(flavorStr, getter_AddRefs(genericDataWrapper), &dataSize);
432 nsPrimitiveHelpers::CreateDataFromPrimitive(flavorStr, genericDataWrapper, &data, dataSize);
433
434 NSString* nativeString;
435 if (data)
436 nativeString = [NSString stringWithCharacters:(const unichar*)data length:(dataSize / sizeof(char16_t))];
437 else
438 nativeString = [NSString string];
439
440 // be nice to Carbon apps, normalize the receiver's contents using Form C.
441 nativeString = [nativeString precomposedStringWithCanonicalMapping];
442
443 [pasteboardOutputDict setObject:nativeString forKey:pboardType];
444
445 nsMemory::Free(data);
446 }
447 else if (flavorStr.EqualsLiteral(kPNGImageMime) || flavorStr.EqualsLiteral(kJPEGImageMime) ||
448 flavorStr.EqualsLiteral(kJPGImageMime) || flavorStr.EqualsLiteral(kGIFImageMime) ||
449 flavorStr.EqualsLiteral(kNativeImageMime)) {
450 uint32_t dataSize = 0;
451 nsCOMPtr<nsISupports> transferSupports;
452 aTransferable->GetTransferData(flavorStr, getter_AddRefs(transferSupports), &dataSize);
453 nsCOMPtr<nsISupportsInterfacePointer> ptrPrimitive(do_QueryInterface(transferSupports));
454 if (!ptrPrimitive)
455 continue;
456
457 nsCOMPtr<nsISupports> primitiveData;
458 ptrPrimitive->GetData(getter_AddRefs(primitiveData));
459
460 nsCOMPtr<imgIContainer> image(do_QueryInterface(primitiveData));
461 if (!image) {
462 NS_WARNING("Image isn't an imgIContainer in transferable");
463 continue;
464 }
465
466 RefPtr<SourceSurface> surface =
467 image->GetFrame(imgIContainer::FRAME_CURRENT,
468 imgIContainer::FLAG_SYNC_DECODE);
469 if (!surface) {
470 continue;
471 }
472 CGImageRef imageRef = NULL;
473 nsresult rv = nsCocoaUtils::CreateCGImageFromSurface(surface, &imageRef);
474 if (NS_FAILED(rv) || !imageRef) {
475 continue;
476 }
477
478 // Convert the CGImageRef to TIFF data.
479 CFMutableDataRef tiffData = CFDataCreateMutable(kCFAllocatorDefault, 0);
480 CGImageDestinationRef destRef = CGImageDestinationCreateWithData(tiffData,
481 CFSTR("public.tiff"),
482 1,
483 NULL);
484 CGImageDestinationAddImage(destRef, imageRef, NULL);
485 bool successfullyConverted = CGImageDestinationFinalize(destRef);
486
487 CGImageRelease(imageRef);
488 if (destRef)
489 CFRelease(destRef);
490
491 if (!successfullyConverted) {
492 if (tiffData)
493 CFRelease(tiffData);
494 continue;
495 }
496
497 [pasteboardOutputDict setObject:(NSMutableData*)tiffData forKey:NSTIFFPboardType];
498 if (tiffData)
499 CFRelease(tiffData);
500 }
501 else if (flavorStr.EqualsLiteral(kFileMime)) {
502 uint32_t len = 0;
503 nsCOMPtr<nsISupports> genericFile;
504 rv = aTransferable->GetTransferData(flavorStr, getter_AddRefs(genericFile), &len);
505 if (NS_FAILED(rv)) {
506 continue;
507 }
508
509 nsCOMPtr<nsIFile> file(do_QueryInterface(genericFile));
510 if (!file) {
511 nsCOMPtr<nsISupportsInterfacePointer> ptr(do_QueryInterface(genericFile));
512
513 if (ptr) {
514 ptr->GetData(getter_AddRefs(genericFile));
515 file = do_QueryInterface(genericFile);
516 }
517 }
518
519 if (!file) {
520 continue;
521 }
522
523 nsAutoString fileURI;
524 rv = file->GetPath(fileURI);
525 if (NS_FAILED(rv)) {
526 continue;
527 }
528
529 NSString* str = nsCocoaUtils::ToNSString(fileURI);
530 NSArray* fileList = [NSArray arrayWithObjects:str, nil];
531 [pasteboardOutputDict setObject:fileList forKey:NSFilenamesPboardType];
532 }
533 else if (flavorStr.EqualsLiteral(kFilePromiseMime)) {
534 [pasteboardOutputDict setObject:[NSArray arrayWithObject:@""] forKey:NSFilesPromisePboardType];
535 }
536 else if (flavorStr.EqualsLiteral(kURLMime)) {
537 uint32_t len = 0;
538 nsCOMPtr<nsISupports> genericURL;
539 rv = aTransferable->GetTransferData(flavorStr, getter_AddRefs(genericURL), &len);
540 nsCOMPtr<nsISupportsString> urlObject(do_QueryInterface(genericURL));
541
542 nsAutoString url;
543 urlObject->GetData(url);
544
545 // A newline embedded in the URL means that the form is actually URL + title.
546 int32_t newlinePos = url.FindChar(char16_t('\n'));
547 if (newlinePos >= 0) {
548 url.Truncate(newlinePos);
549
550 nsAutoString urlTitle;
551 urlObject->GetData(urlTitle);
552 urlTitle.Mid(urlTitle, newlinePos + 1, len - (newlinePos + 1));
553
554 NSString *nativeTitle = [[NSString alloc] initWithCharacters:reinterpret_cast<const unichar*>(urlTitle.get())
555 length:urlTitle.Length()];
556 // be nice to Carbon apps, normalize the receiver's contents using Form C.
557 [pasteboardOutputDict setObject:[nativeTitle precomposedStringWithCanonicalMapping] forKey:kCorePboardType_urln];
558 // Also put the title out as 'urld', since some recipients will look for that.
559 [pasteboardOutputDict setObject:[nativeTitle precomposedStringWithCanonicalMapping] forKey:kCorePboardType_urld];
560 [nativeTitle release];
561 }
562
563 // The Finder doesn't like getting random binary data aka
564 // Unicode, so change it into an escaped URL containing only
565 // ASCII.
566 nsAutoCString utf8Data = NS_ConvertUTF16toUTF8(url.get(), url.Length());
567 nsAutoCString escData;
568 NS_EscapeURL(utf8Data.get(), utf8Data.Length(), esc_OnlyNonASCII|esc_AlwaysCopy, escData);
569
570 // printf("Escaped url is %s, length %d\n", escData.get(), escData.Length());
571
572 NSString *nativeURL = [NSString stringWithUTF8String:escData.get()];
573 [pasteboardOutputDict setObject:nativeURL forKey:kCorePboardType_url];
574 }
575 // If it wasn't a type that we recognize as exportable we don't put it on the system
576 // clipboard. We'll just access it from our cached transferable when we need it.
577 }
578
579 return pasteboardOutputDict;
580
581 NS_OBJC_END_TRY_ABORT_BLOCK_NIL;
582 }
583
584 bool nsClipboard::IsStringType(const nsCString& aMIMEType, NSString** aPasteboardType)
585 {
586 if (aMIMEType.EqualsLiteral(kUnicodeMime) ||
587 aMIMEType.EqualsLiteral(kHTMLMime)) {
588 if (aMIMEType.EqualsLiteral(kUnicodeMime))
589 *aPasteboardType = NSStringPboardType;
590 else
591 *aPasteboardType = NSHTMLPboardType;
592 return true;
593 } else {
594 return false;
595 }
596 }
597
598 NSString* nsClipboard::WrapHtmlForSystemPasteboard(NSString* aString)
599 {
600 NSString* wrapped =
601 [NSString stringWithFormat:
602 @"<html>"
603 "<head>"
604 "<meta http-equiv=\"content-type\" content=\"text/html; charset=utf-8\">"
605 "</head>"
606 "<body>"
607 "%@"
608 "</body>"
609 "</html>", aString];
610 return wrapped;
611 }

mercurial