1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/widget/cocoa/nsClipboard.mm Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,611 @@ 1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +#ifdef MOZ_LOGGING 1.10 +#define FORCE_PR_LOG 1.11 +#endif 1.12 +#include "prlog.h" 1.13 + 1.14 +#include "gfxPlatform.h" 1.15 +#include "nsCOMPtr.h" 1.16 +#include "nsClipboard.h" 1.17 +#include "nsString.h" 1.18 +#include "nsISupportsPrimitives.h" 1.19 +#include "nsXPIDLString.h" 1.20 +#include "nsPrimitiveHelpers.h" 1.21 +#include "nsMemory.h" 1.22 +#include "nsIFile.h" 1.23 +#include "nsStringStream.h" 1.24 +#include "nsDragService.h" 1.25 +#include "nsEscape.h" 1.26 +#include "nsPrintfCString.h" 1.27 +#include "nsObjCExceptions.h" 1.28 +#include "imgIContainer.h" 1.29 +#include "nsCocoaUtils.h" 1.30 + 1.31 +using mozilla::gfx::DataSourceSurface; 1.32 +using mozilla::gfx::SourceSurface; 1.33 +using mozilla::RefPtr; 1.34 + 1.35 +// Screenshots use the (undocumented) png pasteboard type. 1.36 +#define IMAGE_PASTEBOARD_TYPES NSTIFFPboardType, @"Apple PNG pasteboard type", nil 1.37 + 1.38 +#ifdef PR_LOGGING 1.39 +extern PRLogModuleInfo* sCocoaLog; 1.40 +#endif 1.41 + 1.42 +extern void EnsureLogInitialized(); 1.43 + 1.44 +nsClipboard::nsClipboard() : nsBaseClipboard() 1.45 +{ 1.46 + mCachedClipboard = -1; 1.47 + mChangeCount = 0; 1.48 + 1.49 + EnsureLogInitialized(); 1.50 +} 1.51 + 1.52 +nsClipboard::~nsClipboard() 1.53 +{ 1.54 +} 1.55 + 1.56 +// We separate this into its own function because after an @try, all local 1.57 +// variables within that function get marked as volatile, and our C++ type 1.58 +// system doesn't like volatile things. 1.59 +static NSData* 1.60 +GetDataFromPasteboard(NSPasteboard* aPasteboard, NSString* aType) 1.61 +{ 1.62 + NSData *data = nil; 1.63 + @try { 1.64 + data = [aPasteboard dataForType:aType]; 1.65 + } @catch (NSException* e) { 1.66 + NS_WARNING(nsPrintfCString("Exception raised while getting data from the pasteboard: \"%s - %s\"", 1.67 + [[e name] UTF8String], [[e reason] UTF8String]).get()); 1.68 + } 1.69 + return data; 1.70 +} 1.71 + 1.72 +NS_IMETHODIMP 1.73 +nsClipboard::SetNativeClipboardData(int32_t aWhichClipboard) 1.74 +{ 1.75 + NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT; 1.76 + 1.77 + if ((aWhichClipboard != kGlobalClipboard && aWhichClipboard != kFindClipboard) || !mTransferable) 1.78 + return NS_ERROR_FAILURE; 1.79 + 1.80 + mIgnoreEmptyNotification = true; 1.81 + 1.82 + NSDictionary* pasteboardOutputDict = PasteboardDictFromTransferable(mTransferable); 1.83 + if (!pasteboardOutputDict) 1.84 + return NS_ERROR_FAILURE; 1.85 + 1.86 + unsigned int outputCount = [pasteboardOutputDict count]; 1.87 + NSArray* outputKeys = [pasteboardOutputDict allKeys]; 1.88 + NSPasteboard* cocoaPasteboard; 1.89 + if (aWhichClipboard == kFindClipboard) { 1.90 + cocoaPasteboard = [NSPasteboard pasteboardWithName:NSFindPboard]; 1.91 + [cocoaPasteboard declareTypes:[NSArray arrayWithObject:NSStringPboardType] owner:nil]; 1.92 + } else { 1.93 + // Write everything else out to the general pasteboard. 1.94 + cocoaPasteboard = [NSPasteboard generalPasteboard]; 1.95 + [cocoaPasteboard declareTypes:outputKeys owner:nil]; 1.96 + } 1.97 + 1.98 + for (unsigned int i = 0; i < outputCount; i++) { 1.99 + NSString* currentKey = [outputKeys objectAtIndex:i]; 1.100 + id currentValue = [pasteboardOutputDict valueForKey:currentKey]; 1.101 + if (aWhichClipboard == kFindClipboard) { 1.102 + if (currentKey == NSStringPboardType) 1.103 + [cocoaPasteboard setString:currentValue forType:currentKey]; 1.104 + } else { 1.105 + if (currentKey == NSStringPboardType || 1.106 + currentKey == kCorePboardType_url || 1.107 + currentKey == kCorePboardType_urld || 1.108 + currentKey == kCorePboardType_urln) { 1.109 + [cocoaPasteboard setString:currentValue forType:currentKey]; 1.110 + } else if (currentKey == NSHTMLPboardType) { 1.111 + [cocoaPasteboard setString:(nsClipboard::WrapHtmlForSystemPasteboard(currentValue)) 1.112 + forType:currentKey]; 1.113 + } else { 1.114 + [cocoaPasteboard setData:currentValue forType:currentKey]; 1.115 + } 1.116 + } 1.117 + } 1.118 + 1.119 + mCachedClipboard = aWhichClipboard; 1.120 + mChangeCount = [cocoaPasteboard changeCount]; 1.121 + 1.122 + mIgnoreEmptyNotification = false; 1.123 + 1.124 + return NS_OK; 1.125 + 1.126 + NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT; 1.127 +} 1.128 + 1.129 +nsresult 1.130 +nsClipboard::TransferableFromPasteboard(nsITransferable *aTransferable, NSPasteboard *cocoaPasteboard) 1.131 +{ 1.132 + NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT; 1.133 + 1.134 + // get flavor list that includes all acceptable flavors (including ones obtained through conversion) 1.135 + nsCOMPtr<nsISupportsArray> flavorList; 1.136 + nsresult rv = aTransferable->FlavorsTransferableCanImport(getter_AddRefs(flavorList)); 1.137 + if (NS_FAILED(rv)) 1.138 + return NS_ERROR_FAILURE; 1.139 + 1.140 + uint32_t flavorCount; 1.141 + flavorList->Count(&flavorCount); 1.142 + 1.143 + for (uint32_t i = 0; i < flavorCount; i++) { 1.144 + nsCOMPtr<nsISupports> genericFlavor; 1.145 + flavorList->GetElementAt(i, getter_AddRefs(genericFlavor)); 1.146 + nsCOMPtr<nsISupportsCString> currentFlavor(do_QueryInterface(genericFlavor)); 1.147 + if (!currentFlavor) 1.148 + continue; 1.149 + 1.150 + nsXPIDLCString flavorStr; 1.151 + currentFlavor->ToString(getter_Copies(flavorStr)); // i has a flavr 1.152 + 1.153 + // printf("looking for clipboard data of type %s\n", flavorStr.get()); 1.154 + 1.155 + NSString *pboardType = nil; 1.156 + if (nsClipboard::IsStringType(flavorStr, &pboardType)) { 1.157 + NSString* pString = [cocoaPasteboard stringForType:pboardType]; 1.158 + if (!pString) 1.159 + continue; 1.160 + 1.161 + NSData* stringData = [pString dataUsingEncoding:NSUnicodeStringEncoding]; 1.162 + unsigned int dataLength = [stringData length]; 1.163 + void* clipboardDataPtr = malloc(dataLength); 1.164 + if (!clipboardDataPtr) 1.165 + return NS_ERROR_OUT_OF_MEMORY; 1.166 + [stringData getBytes:clipboardDataPtr]; 1.167 + 1.168 + // The DOM only wants LF, so convert from MacOS line endings to DOM line endings. 1.169 + int32_t signedDataLength = dataLength; 1.170 + nsLinebreakHelpers::ConvertPlatformToDOMLinebreaks(flavorStr, &clipboardDataPtr, &signedDataLength); 1.171 + dataLength = signedDataLength; 1.172 + 1.173 + // skip BOM (Byte Order Mark to distinguish little or big endian) 1.174 + char16_t* clipboardDataPtrNoBOM = (char16_t*)clipboardDataPtr; 1.175 + if ((dataLength > 2) && 1.176 + ((clipboardDataPtrNoBOM[0] == 0xFEFF) || 1.177 + (clipboardDataPtrNoBOM[0] == 0xFFFE))) { 1.178 + dataLength -= sizeof(char16_t); 1.179 + clipboardDataPtrNoBOM += 1; 1.180 + } 1.181 + 1.182 + nsCOMPtr<nsISupports> genericDataWrapper; 1.183 + nsPrimitiveHelpers::CreatePrimitiveForData(flavorStr, clipboardDataPtrNoBOM, dataLength, 1.184 + getter_AddRefs(genericDataWrapper)); 1.185 + aTransferable->SetTransferData(flavorStr, genericDataWrapper, dataLength); 1.186 + free(clipboardDataPtr); 1.187 + break; 1.188 + } 1.189 + else if (flavorStr.EqualsLiteral(kJPEGImageMime) || 1.190 + flavorStr.EqualsLiteral(kJPGImageMime) || 1.191 + flavorStr.EqualsLiteral(kPNGImageMime) || 1.192 + flavorStr.EqualsLiteral(kGIFImageMime)) { 1.193 + // Figure out if there's data on the pasteboard we can grab (sanity check) 1.194 + NSString *type = [cocoaPasteboard availableTypeFromArray:[NSArray arrayWithObjects:IMAGE_PASTEBOARD_TYPES]]; 1.195 + if (!type) 1.196 + continue; 1.197 + 1.198 + // Read data off the clipboard 1.199 + NSData *pasteboardData = GetDataFromPasteboard(cocoaPasteboard, type); 1.200 + if (!pasteboardData) 1.201 + continue; 1.202 + 1.203 + // Figure out what type we're converting to 1.204 + CFStringRef outputType = NULL; 1.205 + if (flavorStr.EqualsLiteral(kJPEGImageMime) || 1.206 + flavorStr.EqualsLiteral(kJPGImageMime)) 1.207 + outputType = CFSTR("public.jpeg"); 1.208 + else if (flavorStr.EqualsLiteral(kPNGImageMime)) 1.209 + outputType = CFSTR("public.png"); 1.210 + else if (flavorStr.EqualsLiteral(kGIFImageMime)) 1.211 + outputType = CFSTR("com.compuserve.gif"); 1.212 + else 1.213 + continue; 1.214 + 1.215 + // Use ImageIO to interpret the data on the clipboard and transcode. 1.216 + // Note that ImageIO, like all CF APIs, allows NULLs to propagate freely 1.217 + // and safely in most cases (like ObjC). A notable exception is CFRelease. 1.218 + NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys: 1.219 + (NSNumber*)kCFBooleanTrue, kCGImageSourceShouldAllowFloat, 1.220 + (type == NSTIFFPboardType ? @"public.tiff" : @"public.png"), 1.221 + kCGImageSourceTypeIdentifierHint, nil]; 1.222 + 1.223 + CGImageSourceRef source = CGImageSourceCreateWithData((CFDataRef)pasteboardData, 1.224 + (CFDictionaryRef)options); 1.225 + NSMutableData *encodedData = [NSMutableData data]; 1.226 + CGImageDestinationRef dest = CGImageDestinationCreateWithData((CFMutableDataRef)encodedData, 1.227 + outputType, 1.228 + 1, NULL); 1.229 + CGImageDestinationAddImageFromSource(dest, source, 0, NULL); 1.230 + bool successfullyConverted = CGImageDestinationFinalize(dest); 1.231 + 1.232 + if (successfullyConverted) { 1.233 + // Put the converted data in a form Gecko can understand 1.234 + nsCOMPtr<nsIInputStream> byteStream; 1.235 + NS_NewByteInputStream(getter_AddRefs(byteStream), (const char*)[encodedData bytes], 1.236 + [encodedData length], NS_ASSIGNMENT_COPY); 1.237 + 1.238 + aTransferable->SetTransferData(flavorStr, byteStream, sizeof(nsIInputStream*)); 1.239 + } 1.240 + 1.241 + if (dest) 1.242 + CFRelease(dest); 1.243 + if (source) 1.244 + CFRelease(source); 1.245 + 1.246 + if (successfullyConverted) 1.247 + break; 1.248 + else 1.249 + continue; 1.250 + } 1.251 + } 1.252 + 1.253 + return NS_OK; 1.254 + 1.255 + NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT; 1.256 +} 1.257 + 1.258 +NS_IMETHODIMP 1.259 +nsClipboard::GetNativeClipboardData(nsITransferable* aTransferable, int32_t aWhichClipboard) 1.260 +{ 1.261 + NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT; 1.262 + 1.263 + if ((aWhichClipboard != kGlobalClipboard && aWhichClipboard != kFindClipboard) || !aTransferable) 1.264 + return NS_ERROR_FAILURE; 1.265 + 1.266 + NSPasteboard* cocoaPasteboard; 1.267 + if (aWhichClipboard == kFindClipboard) { 1.268 + cocoaPasteboard = [NSPasteboard pasteboardWithName:NSFindPboard]; 1.269 + } else { 1.270 + cocoaPasteboard = [NSPasteboard generalPasteboard]; 1.271 + } 1.272 + if (!cocoaPasteboard) 1.273 + return NS_ERROR_FAILURE; 1.274 + 1.275 + // get flavor list that includes all acceptable flavors (including ones obtained through conversion) 1.276 + nsCOMPtr<nsISupportsArray> flavorList; 1.277 + nsresult rv = aTransferable->FlavorsTransferableCanImport(getter_AddRefs(flavorList)); 1.278 + if (NS_FAILED(rv)) 1.279 + return NS_ERROR_FAILURE; 1.280 + 1.281 + uint32_t flavorCount; 1.282 + flavorList->Count(&flavorCount); 1.283 + 1.284 + // If we were the last ones to put something on the pasteboard, then just use the cached 1.285 + // transferable. Otherwise clear it because it isn't relevant any more. 1.286 + if (mCachedClipboard == aWhichClipboard && 1.287 + mChangeCount == [cocoaPasteboard changeCount]) { 1.288 + if (mTransferable) { 1.289 + for (uint32_t i = 0; i < flavorCount; i++) { 1.290 + nsCOMPtr<nsISupports> genericFlavor; 1.291 + flavorList->GetElementAt(i, getter_AddRefs(genericFlavor)); 1.292 + nsCOMPtr<nsISupportsCString> currentFlavor(do_QueryInterface(genericFlavor)); 1.293 + if (!currentFlavor) 1.294 + continue; 1.295 + 1.296 + nsXPIDLCString flavorStr; 1.297 + currentFlavor->ToString(getter_Copies(flavorStr)); 1.298 + 1.299 + nsCOMPtr<nsISupports> dataSupports; 1.300 + uint32_t dataSize = 0; 1.301 + rv = mTransferable->GetTransferData(flavorStr, getter_AddRefs(dataSupports), &dataSize); 1.302 + if (NS_SUCCEEDED(rv)) { 1.303 + aTransferable->SetTransferData(flavorStr, dataSupports, dataSize); 1.304 + return NS_OK; // maybe try to fill in more types? Is there a point? 1.305 + } 1.306 + } 1.307 + } 1.308 + } else { 1.309 + nsBaseClipboard::EmptyClipboard(aWhichClipboard); 1.310 + } 1.311 + 1.312 + // at this point we can't satisfy the request from cache data so let's look 1.313 + // for things other people put on the system clipboard 1.314 + 1.315 + return nsClipboard::TransferableFromPasteboard(aTransferable, cocoaPasteboard); 1.316 + 1.317 + NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT; 1.318 +} 1.319 + 1.320 +// returns true if we have *any* of the passed in flavors available for pasting 1.321 +NS_IMETHODIMP 1.322 +nsClipboard::HasDataMatchingFlavors(const char** aFlavorList, uint32_t aLength, 1.323 + int32_t aWhichClipboard, bool* outResult) 1.324 +{ 1.325 + NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT; 1.326 + 1.327 + *outResult = false; 1.328 + 1.329 + if ((aWhichClipboard != kGlobalClipboard) || !aFlavorList) 1.330 + return NS_OK; 1.331 + 1.332 + // first see if we have data for this in our cached transferable 1.333 + if (mTransferable) { 1.334 + nsCOMPtr<nsISupportsArray> transferableFlavorList; 1.335 + nsresult rv = mTransferable->FlavorsTransferableCanImport(getter_AddRefs(transferableFlavorList)); 1.336 + if (NS_SUCCEEDED(rv)) { 1.337 + uint32_t transferableFlavorCount; 1.338 + transferableFlavorList->Count(&transferableFlavorCount); 1.339 + for (uint32_t j = 0; j < transferableFlavorCount; j++) { 1.340 + nsCOMPtr<nsISupports> transferableFlavorSupports; 1.341 + transferableFlavorList->GetElementAt(j, getter_AddRefs(transferableFlavorSupports)); 1.342 + nsCOMPtr<nsISupportsCString> currentTransferableFlavor(do_QueryInterface(transferableFlavorSupports)); 1.343 + if (!currentTransferableFlavor) 1.344 + continue; 1.345 + nsXPIDLCString transferableFlavorStr; 1.346 + currentTransferableFlavor->ToString(getter_Copies(transferableFlavorStr)); 1.347 + 1.348 + for (uint32_t k = 0; k < aLength; k++) { 1.349 + if (transferableFlavorStr.Equals(aFlavorList[k])) { 1.350 + *outResult = true; 1.351 + return NS_OK; 1.352 + } 1.353 + } 1.354 + } 1.355 + } 1.356 + } 1.357 + 1.358 + NSPasteboard* generalPBoard = [NSPasteboard generalPasteboard]; 1.359 + 1.360 + for (uint32_t i = 0; i < aLength; i++) { 1.361 + nsDependentCString mimeType(aFlavorList[i]); 1.362 + NSString *pboardType = nil; 1.363 + 1.364 + if (nsClipboard::IsStringType(mimeType, &pboardType)) { 1.365 + NSString* availableType = [generalPBoard availableTypeFromArray:[NSArray arrayWithObject:pboardType]]; 1.366 + if (availableType && [availableType isEqualToString:pboardType]) { 1.367 + *outResult = true; 1.368 + break; 1.369 + } 1.370 + } else if (!strcmp(aFlavorList[i], kJPEGImageMime) || 1.371 + !strcmp(aFlavorList[i], kJPGImageMime) || 1.372 + !strcmp(aFlavorList[i], kPNGImageMime) || 1.373 + !strcmp(aFlavorList[i], kGIFImageMime)) { 1.374 + NSString* availableType = [generalPBoard availableTypeFromArray: 1.375 + [NSArray arrayWithObjects:IMAGE_PASTEBOARD_TYPES]]; 1.376 + if (availableType) { 1.377 + *outResult = true; 1.378 + break; 1.379 + } 1.380 + } 1.381 + } 1.382 + 1.383 + return NS_OK; 1.384 + 1.385 + NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT; 1.386 +} 1.387 + 1.388 +NS_IMETHODIMP 1.389 +nsClipboard::SupportsFindClipboard(bool *_retval) 1.390 +{ 1.391 + NS_ENSURE_ARG_POINTER(_retval); 1.392 + *_retval = true; 1.393 + return NS_OK; 1.394 +} 1.395 + 1.396 +// This function converts anything that other applications might understand into the system format 1.397 +// and puts it into a dictionary which it returns. 1.398 +// static 1.399 +NSDictionary* 1.400 +nsClipboard::PasteboardDictFromTransferable(nsITransferable* aTransferable) 1.401 +{ 1.402 + NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL; 1.403 + 1.404 + if (!aTransferable) 1.405 + return nil; 1.406 + 1.407 + NSMutableDictionary* pasteboardOutputDict = [NSMutableDictionary dictionary]; 1.408 + 1.409 + nsCOMPtr<nsISupportsArray> flavorList; 1.410 + nsresult rv = aTransferable->FlavorsTransferableCanExport(getter_AddRefs(flavorList)); 1.411 + if (NS_FAILED(rv)) 1.412 + return nil; 1.413 + 1.414 + uint32_t flavorCount; 1.415 + flavorList->Count(&flavorCount); 1.416 + for (uint32_t i = 0; i < flavorCount; i++) { 1.417 + nsCOMPtr<nsISupports> genericFlavor; 1.418 + flavorList->GetElementAt(i, getter_AddRefs(genericFlavor)); 1.419 + nsCOMPtr<nsISupportsCString> currentFlavor(do_QueryInterface(genericFlavor)); 1.420 + if (!currentFlavor) 1.421 + continue; 1.422 + 1.423 + nsXPIDLCString flavorStr; 1.424 + currentFlavor->ToString(getter_Copies(flavorStr)); 1.425 + 1.426 + PR_LOG(sCocoaLog, PR_LOG_ALWAYS, ("writing out clipboard data of type %s (%d)\n", flavorStr.get(), i)); 1.427 + 1.428 + NSString *pboardType = nil; 1.429 + 1.430 + if (nsClipboard::IsStringType(flavorStr, &pboardType)) { 1.431 + void* data = nullptr; 1.432 + uint32_t dataSize = 0; 1.433 + nsCOMPtr<nsISupports> genericDataWrapper; 1.434 + rv = aTransferable->GetTransferData(flavorStr, getter_AddRefs(genericDataWrapper), &dataSize); 1.435 + nsPrimitiveHelpers::CreateDataFromPrimitive(flavorStr, genericDataWrapper, &data, dataSize); 1.436 + 1.437 + NSString* nativeString; 1.438 + if (data) 1.439 + nativeString = [NSString stringWithCharacters:(const unichar*)data length:(dataSize / sizeof(char16_t))]; 1.440 + else 1.441 + nativeString = [NSString string]; 1.442 + 1.443 + // be nice to Carbon apps, normalize the receiver's contents using Form C. 1.444 + nativeString = [nativeString precomposedStringWithCanonicalMapping]; 1.445 + 1.446 + [pasteboardOutputDict setObject:nativeString forKey:pboardType]; 1.447 + 1.448 + nsMemory::Free(data); 1.449 + } 1.450 + else if (flavorStr.EqualsLiteral(kPNGImageMime) || flavorStr.EqualsLiteral(kJPEGImageMime) || 1.451 + flavorStr.EqualsLiteral(kJPGImageMime) || flavorStr.EqualsLiteral(kGIFImageMime) || 1.452 + flavorStr.EqualsLiteral(kNativeImageMime)) { 1.453 + uint32_t dataSize = 0; 1.454 + nsCOMPtr<nsISupports> transferSupports; 1.455 + aTransferable->GetTransferData(flavorStr, getter_AddRefs(transferSupports), &dataSize); 1.456 + nsCOMPtr<nsISupportsInterfacePointer> ptrPrimitive(do_QueryInterface(transferSupports)); 1.457 + if (!ptrPrimitive) 1.458 + continue; 1.459 + 1.460 + nsCOMPtr<nsISupports> primitiveData; 1.461 + ptrPrimitive->GetData(getter_AddRefs(primitiveData)); 1.462 + 1.463 + nsCOMPtr<imgIContainer> image(do_QueryInterface(primitiveData)); 1.464 + if (!image) { 1.465 + NS_WARNING("Image isn't an imgIContainer in transferable"); 1.466 + continue; 1.467 + } 1.468 + 1.469 + RefPtr<SourceSurface> surface = 1.470 + image->GetFrame(imgIContainer::FRAME_CURRENT, 1.471 + imgIContainer::FLAG_SYNC_DECODE); 1.472 + if (!surface) { 1.473 + continue; 1.474 + } 1.475 + CGImageRef imageRef = NULL; 1.476 + nsresult rv = nsCocoaUtils::CreateCGImageFromSurface(surface, &imageRef); 1.477 + if (NS_FAILED(rv) || !imageRef) { 1.478 + continue; 1.479 + } 1.480 + 1.481 + // Convert the CGImageRef to TIFF data. 1.482 + CFMutableDataRef tiffData = CFDataCreateMutable(kCFAllocatorDefault, 0); 1.483 + CGImageDestinationRef destRef = CGImageDestinationCreateWithData(tiffData, 1.484 + CFSTR("public.tiff"), 1.485 + 1, 1.486 + NULL); 1.487 + CGImageDestinationAddImage(destRef, imageRef, NULL); 1.488 + bool successfullyConverted = CGImageDestinationFinalize(destRef); 1.489 + 1.490 + CGImageRelease(imageRef); 1.491 + if (destRef) 1.492 + CFRelease(destRef); 1.493 + 1.494 + if (!successfullyConverted) { 1.495 + if (tiffData) 1.496 + CFRelease(tiffData); 1.497 + continue; 1.498 + } 1.499 + 1.500 + [pasteboardOutputDict setObject:(NSMutableData*)tiffData forKey:NSTIFFPboardType]; 1.501 + if (tiffData) 1.502 + CFRelease(tiffData); 1.503 + } 1.504 + else if (flavorStr.EqualsLiteral(kFileMime)) { 1.505 + uint32_t len = 0; 1.506 + nsCOMPtr<nsISupports> genericFile; 1.507 + rv = aTransferable->GetTransferData(flavorStr, getter_AddRefs(genericFile), &len); 1.508 + if (NS_FAILED(rv)) { 1.509 + continue; 1.510 + } 1.511 + 1.512 + nsCOMPtr<nsIFile> file(do_QueryInterface(genericFile)); 1.513 + if (!file) { 1.514 + nsCOMPtr<nsISupportsInterfacePointer> ptr(do_QueryInterface(genericFile)); 1.515 + 1.516 + if (ptr) { 1.517 + ptr->GetData(getter_AddRefs(genericFile)); 1.518 + file = do_QueryInterface(genericFile); 1.519 + } 1.520 + } 1.521 + 1.522 + if (!file) { 1.523 + continue; 1.524 + } 1.525 + 1.526 + nsAutoString fileURI; 1.527 + rv = file->GetPath(fileURI); 1.528 + if (NS_FAILED(rv)) { 1.529 + continue; 1.530 + } 1.531 + 1.532 + NSString* str = nsCocoaUtils::ToNSString(fileURI); 1.533 + NSArray* fileList = [NSArray arrayWithObjects:str, nil]; 1.534 + [pasteboardOutputDict setObject:fileList forKey:NSFilenamesPboardType]; 1.535 + } 1.536 + else if (flavorStr.EqualsLiteral(kFilePromiseMime)) { 1.537 + [pasteboardOutputDict setObject:[NSArray arrayWithObject:@""] forKey:NSFilesPromisePboardType]; 1.538 + } 1.539 + else if (flavorStr.EqualsLiteral(kURLMime)) { 1.540 + uint32_t len = 0; 1.541 + nsCOMPtr<nsISupports> genericURL; 1.542 + rv = aTransferable->GetTransferData(flavorStr, getter_AddRefs(genericURL), &len); 1.543 + nsCOMPtr<nsISupportsString> urlObject(do_QueryInterface(genericURL)); 1.544 + 1.545 + nsAutoString url; 1.546 + urlObject->GetData(url); 1.547 + 1.548 + // A newline embedded in the URL means that the form is actually URL + title. 1.549 + int32_t newlinePos = url.FindChar(char16_t('\n')); 1.550 + if (newlinePos >= 0) { 1.551 + url.Truncate(newlinePos); 1.552 + 1.553 + nsAutoString urlTitle; 1.554 + urlObject->GetData(urlTitle); 1.555 + urlTitle.Mid(urlTitle, newlinePos + 1, len - (newlinePos + 1)); 1.556 + 1.557 + NSString *nativeTitle = [[NSString alloc] initWithCharacters:reinterpret_cast<const unichar*>(urlTitle.get()) 1.558 + length:urlTitle.Length()]; 1.559 + // be nice to Carbon apps, normalize the receiver's contents using Form C. 1.560 + [pasteboardOutputDict setObject:[nativeTitle precomposedStringWithCanonicalMapping] forKey:kCorePboardType_urln]; 1.561 + // Also put the title out as 'urld', since some recipients will look for that. 1.562 + [pasteboardOutputDict setObject:[nativeTitle precomposedStringWithCanonicalMapping] forKey:kCorePboardType_urld]; 1.563 + [nativeTitle release]; 1.564 + } 1.565 + 1.566 + // The Finder doesn't like getting random binary data aka 1.567 + // Unicode, so change it into an escaped URL containing only 1.568 + // ASCII. 1.569 + nsAutoCString utf8Data = NS_ConvertUTF16toUTF8(url.get(), url.Length()); 1.570 + nsAutoCString escData; 1.571 + NS_EscapeURL(utf8Data.get(), utf8Data.Length(), esc_OnlyNonASCII|esc_AlwaysCopy, escData); 1.572 + 1.573 + // printf("Escaped url is %s, length %d\n", escData.get(), escData.Length()); 1.574 + 1.575 + NSString *nativeURL = [NSString stringWithUTF8String:escData.get()]; 1.576 + [pasteboardOutputDict setObject:nativeURL forKey:kCorePboardType_url]; 1.577 + } 1.578 + // If it wasn't a type that we recognize as exportable we don't put it on the system 1.579 + // clipboard. We'll just access it from our cached transferable when we need it. 1.580 + } 1.581 + 1.582 + return pasteboardOutputDict; 1.583 + 1.584 + NS_OBJC_END_TRY_ABORT_BLOCK_NIL; 1.585 +} 1.586 + 1.587 +bool nsClipboard::IsStringType(const nsCString& aMIMEType, NSString** aPasteboardType) 1.588 +{ 1.589 + if (aMIMEType.EqualsLiteral(kUnicodeMime) || 1.590 + aMIMEType.EqualsLiteral(kHTMLMime)) { 1.591 + if (aMIMEType.EqualsLiteral(kUnicodeMime)) 1.592 + *aPasteboardType = NSStringPboardType; 1.593 + else 1.594 + *aPasteboardType = NSHTMLPboardType; 1.595 + return true; 1.596 + } else { 1.597 + return false; 1.598 + } 1.599 +} 1.600 + 1.601 +NSString* nsClipboard::WrapHtmlForSystemPasteboard(NSString* aString) 1.602 +{ 1.603 + NSString* wrapped = 1.604 + [NSString stringWithFormat: 1.605 + @"<html>" 1.606 + "<head>" 1.607 + "<meta http-equiv=\"content-type\" content=\"text/html; charset=utf-8\">" 1.608 + "</head>" 1.609 + "<body>" 1.610 + "%@" 1.611 + "</body>" 1.612 + "</html>", aString]; 1.613 + return wrapped; 1.614 +}