widget/cocoa/nsClipboard.mm

Wed, 31 Dec 2014 06:55:50 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:55:50 +0100
changeset 2
7e26c7da4463
permissions
-rw-r--r--

Added tag UPSTREAM_283F7C6 for changeset ca08bd8f51b2

     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/. */
     6 #ifdef MOZ_LOGGING
     7 #define FORCE_PR_LOG
     8 #endif
     9 #include "prlog.h"
    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"
    28 using mozilla::gfx::DataSourceSurface;
    29 using mozilla::gfx::SourceSurface;
    30 using mozilla::RefPtr;
    32 // Screenshots use the (undocumented) png pasteboard type.
    33 #define IMAGE_PASTEBOARD_TYPES NSTIFFPboardType, @"Apple PNG pasteboard type", nil
    35 #ifdef PR_LOGGING
    36 extern PRLogModuleInfo* sCocoaLog;
    37 #endif
    39 extern void EnsureLogInitialized();
    41 nsClipboard::nsClipboard() : nsBaseClipboard()
    42 {
    43   mCachedClipboard = -1;
    44   mChangeCount = 0;
    46   EnsureLogInitialized();
    47 }
    49 nsClipboard::~nsClipboard()
    50 {
    51 }
    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 }
    69 NS_IMETHODIMP
    70 nsClipboard::SetNativeClipboardData(int32_t aWhichClipboard)
    71 {
    72   NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
    74   if ((aWhichClipboard != kGlobalClipboard && aWhichClipboard != kFindClipboard) || !mTransferable)
    75     return NS_ERROR_FAILURE;
    77   mIgnoreEmptyNotification = true;
    79   NSDictionary* pasteboardOutputDict = PasteboardDictFromTransferable(mTransferable);
    80   if (!pasteboardOutputDict)
    81     return NS_ERROR_FAILURE;
    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   }
    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   }
   116   mCachedClipboard = aWhichClipboard;
   117   mChangeCount = [cocoaPasteboard changeCount];
   119   mIgnoreEmptyNotification = false;
   121   return NS_OK;
   123   NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
   124 }
   126 nsresult
   127 nsClipboard::TransferableFromPasteboard(nsITransferable *aTransferable, NSPasteboard *cocoaPasteboard)
   128 {
   129   NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
   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;
   137   uint32_t flavorCount;
   138   flavorList->Count(&flavorCount);
   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;
   147     nsXPIDLCString flavorStr;
   148     currentFlavor->ToString(getter_Copies(flavorStr)); // i has a flavr
   150     // printf("looking for clipboard data of type %s\n", flavorStr.get());
   152     NSString *pboardType = nil;
   153     if (nsClipboard::IsStringType(flavorStr, &pboardType)) {
   154       NSString* pString = [cocoaPasteboard stringForType:pboardType];
   155       if (!pString)
   156         continue;
   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];
   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;
   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       }
   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;
   195       // Read data off the clipboard
   196       NSData *pasteboardData = GetDataFromPasteboard(cocoaPasteboard, type);
   197       if (!pasteboardData)
   198         continue;
   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;
   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];
   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);
   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);
   235         aTransferable->SetTransferData(flavorStr, byteStream, sizeof(nsIInputStream*));
   236       }
   238       if (dest)
   239         CFRelease(dest);
   240       if (source)
   241         CFRelease(source);
   243       if (successfullyConverted)
   244         break;
   245       else
   246         continue;
   247     }
   248   }
   250   return NS_OK;
   252   NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
   253 }
   255 NS_IMETHODIMP
   256 nsClipboard::GetNativeClipboardData(nsITransferable* aTransferable, int32_t aWhichClipboard)
   257 {
   258   NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
   260   if ((aWhichClipboard != kGlobalClipboard && aWhichClipboard != kFindClipboard) || !aTransferable)
   261     return NS_ERROR_FAILURE;
   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;
   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;
   278   uint32_t flavorCount;
   279   flavorList->Count(&flavorCount);
   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;
   293         nsXPIDLCString flavorStr;
   294         currentFlavor->ToString(getter_Copies(flavorStr));
   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   }
   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
   312   return nsClipboard::TransferableFromPasteboard(aTransferable, cocoaPasteboard);
   314   NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
   315 }
   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;
   324   *outResult = false;
   326   if ((aWhichClipboard != kGlobalClipboard) || !aFlavorList)
   327     return NS_OK;
   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));
   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   }
   355   NSPasteboard* generalPBoard = [NSPasteboard generalPasteboard];
   357   for (uint32_t i = 0; i < aLength; i++) {
   358     nsDependentCString mimeType(aFlavorList[i]);
   359     NSString *pboardType = nil;
   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   }
   380   return NS_OK;
   382   NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
   383 }
   385 NS_IMETHODIMP
   386 nsClipboard::SupportsFindClipboard(bool *_retval)
   387 {
   388   NS_ENSURE_ARG_POINTER(_retval);
   389   *_retval = true;
   390   return NS_OK;
   391 }
   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;
   401   if (!aTransferable)
   402     return nil;
   404   NSMutableDictionary* pasteboardOutputDict = [NSMutableDictionary dictionary];
   406   nsCOMPtr<nsISupportsArray> flavorList;
   407   nsresult rv = aTransferable->FlavorsTransferableCanExport(getter_AddRefs(flavorList));
   408   if (NS_FAILED(rv))
   409     return nil;
   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;
   420     nsXPIDLCString flavorStr;
   421     currentFlavor->ToString(getter_Copies(flavorStr));
   423     PR_LOG(sCocoaLog, PR_LOG_ALWAYS, ("writing out clipboard data of type %s (%d)\n", flavorStr.get(), i));
   425     NSString *pboardType = nil;
   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);
   434       NSString* nativeString;
   435       if (data)
   436         nativeString = [NSString stringWithCharacters:(const unichar*)data length:(dataSize / sizeof(char16_t))];
   437       else
   438         nativeString = [NSString string];
   440       // be nice to Carbon apps, normalize the receiver's contents using Form C.
   441       nativeString = [nativeString precomposedStringWithCanonicalMapping];
   443       [pasteboardOutputDict setObject:nativeString forKey:pboardType];
   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;
   457       nsCOMPtr<nsISupports> primitiveData;
   458       ptrPrimitive->GetData(getter_AddRefs(primitiveData));
   460       nsCOMPtr<imgIContainer> image(do_QueryInterface(primitiveData));
   461       if (!image) {
   462         NS_WARNING("Image isn't an imgIContainer in transferable");
   463         continue;
   464       }
   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       }
   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);
   487       CGImageRelease(imageRef);
   488       if (destRef)
   489         CFRelease(destRef);
   491       if (!successfullyConverted) {
   492         if (tiffData)
   493           CFRelease(tiffData);
   494         continue;
   495       }
   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       }
   509       nsCOMPtr<nsIFile> file(do_QueryInterface(genericFile));
   510       if (!file) {
   511         nsCOMPtr<nsISupportsInterfacePointer> ptr(do_QueryInterface(genericFile));
   513         if (ptr) {
   514           ptr->GetData(getter_AddRefs(genericFile));
   515           file = do_QueryInterface(genericFile);
   516         }
   517       }
   519       if (!file) {
   520         continue;
   521       }
   523       nsAutoString fileURI;
   524       rv = file->GetPath(fileURI);
   525       if (NS_FAILED(rv)) {
   526         continue;
   527       }
   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));
   542       nsAutoString url;
   543       urlObject->GetData(url);
   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);
   550         nsAutoString urlTitle;
   551         urlObject->GetData(urlTitle);
   552         urlTitle.Mid(urlTitle, newlinePos + 1, len - (newlinePos + 1));
   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       }
   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);
   570       // printf("Escaped url is %s, length %d\n", escData.get(), escData.Length());
   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   }
   579   return pasteboardOutputDict;
   581   NS_OBJC_END_TRY_ABORT_BLOCK_NIL;
   582 }
   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 }
   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