mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
5d7f3c7007
Backed out changeset 009ae35b0c67 (bug 806819) Backed out changeset 5a57f87f5061 (bug 806819) Backed out changeset f06cd735b5b3 (bug 806819) Backed out changeset e25a2a8d4af4 (bug 806819) Backed out changeset 70a167982c3f (bug 806819)
612 lines
22 KiB
Plaintext
612 lines
22 KiB
Plaintext
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
|
#ifdef MOZ_LOGGING
|
|
#define FORCE_PR_LOG
|
|
#endif
|
|
#include "prlog.h"
|
|
|
|
#include "gfxPlatform.h"
|
|
#include "nsCOMPtr.h"
|
|
#include "nsClipboard.h"
|
|
#include "nsString.h"
|
|
#include "nsISupportsPrimitives.h"
|
|
#include "nsXPIDLString.h"
|
|
#include "nsPrimitiveHelpers.h"
|
|
#include "nsMemory.h"
|
|
#include "nsIFile.h"
|
|
#include "nsStringStream.h"
|
|
#include "nsDragService.h"
|
|
#include "nsEscape.h"
|
|
#include "nsPrintfCString.h"
|
|
#include "nsObjCExceptions.h"
|
|
#include "imgIContainer.h"
|
|
#include "nsCocoaUtils.h"
|
|
|
|
using mozilla::gfx::DataSourceSurface;
|
|
using mozilla::gfx::SourceSurface;
|
|
using mozilla::RefPtr;
|
|
|
|
// Screenshots use the (undocumented) png pasteboard type.
|
|
#define IMAGE_PASTEBOARD_TYPES NSTIFFPboardType, @"Apple PNG pasteboard type", nil
|
|
|
|
#ifdef PR_LOGGING
|
|
extern PRLogModuleInfo* sCocoaLog;
|
|
#endif
|
|
|
|
extern void EnsureLogInitialized();
|
|
|
|
nsClipboard::nsClipboard() : nsBaseClipboard()
|
|
{
|
|
mCachedClipboard = -1;
|
|
mChangeCount = 0;
|
|
|
|
EnsureLogInitialized();
|
|
}
|
|
|
|
nsClipboard::~nsClipboard()
|
|
{
|
|
}
|
|
|
|
// We separate this into its own function because after an @try, all local
|
|
// variables within that function get marked as volatile, and our C++ type
|
|
// system doesn't like volatile things.
|
|
static NSData*
|
|
GetDataFromPasteboard(NSPasteboard* aPasteboard, NSString* aType)
|
|
{
|
|
NSData *data = nil;
|
|
@try {
|
|
data = [aPasteboard dataForType:aType];
|
|
} @catch (NSException* e) {
|
|
NS_WARNING(nsPrintfCString("Exception raised while getting data from the pasteboard: \"%s - %s\"",
|
|
[[e name] UTF8String], [[e reason] UTF8String]).get());
|
|
}
|
|
return data;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsClipboard::SetNativeClipboardData(int32_t aWhichClipboard)
|
|
{
|
|
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
|
|
|
|
if ((aWhichClipboard != kGlobalClipboard && aWhichClipboard != kFindClipboard) || !mTransferable)
|
|
return NS_ERROR_FAILURE;
|
|
|
|
mIgnoreEmptyNotification = true;
|
|
|
|
NSDictionary* pasteboardOutputDict = PasteboardDictFromTransferable(mTransferable);
|
|
if (!pasteboardOutputDict)
|
|
return NS_ERROR_FAILURE;
|
|
|
|
unsigned int outputCount = [pasteboardOutputDict count];
|
|
NSArray* outputKeys = [pasteboardOutputDict allKeys];
|
|
NSPasteboard* cocoaPasteboard;
|
|
if (aWhichClipboard == kFindClipboard) {
|
|
cocoaPasteboard = [NSPasteboard pasteboardWithName:NSFindPboard];
|
|
[cocoaPasteboard declareTypes:[NSArray arrayWithObject:NSStringPboardType] owner:nil];
|
|
} else {
|
|
// Write everything else out to the general pasteboard.
|
|
cocoaPasteboard = [NSPasteboard generalPasteboard];
|
|
[cocoaPasteboard declareTypes:outputKeys owner:nil];
|
|
}
|
|
|
|
for (unsigned int i = 0; i < outputCount; i++) {
|
|
NSString* currentKey = [outputKeys objectAtIndex:i];
|
|
id currentValue = [pasteboardOutputDict valueForKey:currentKey];
|
|
if (aWhichClipboard == kFindClipboard) {
|
|
if (currentKey == NSStringPboardType)
|
|
[cocoaPasteboard setString:currentValue forType:currentKey];
|
|
} else {
|
|
if (currentKey == NSStringPboardType ||
|
|
currentKey == kCorePboardType_url ||
|
|
currentKey == kCorePboardType_urld ||
|
|
currentKey == kCorePboardType_urln) {
|
|
[cocoaPasteboard setString:currentValue forType:currentKey];
|
|
} else if (currentKey == NSHTMLPboardType) {
|
|
[cocoaPasteboard setString:(nsClipboard::WrapHtmlForSystemPasteboard(currentValue))
|
|
forType:currentKey];
|
|
} else {
|
|
[cocoaPasteboard setData:currentValue forType:currentKey];
|
|
}
|
|
}
|
|
}
|
|
|
|
mCachedClipboard = aWhichClipboard;
|
|
mChangeCount = [cocoaPasteboard changeCount];
|
|
|
|
mIgnoreEmptyNotification = false;
|
|
|
|
return NS_OK;
|
|
|
|
NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
|
|
}
|
|
|
|
nsresult
|
|
nsClipboard::TransferableFromPasteboard(nsITransferable *aTransferable, NSPasteboard *cocoaPasteboard)
|
|
{
|
|
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
|
|
|
|
// get flavor list that includes all acceptable flavors (including ones obtained through conversion)
|
|
nsCOMPtr<nsISupportsArray> flavorList;
|
|
nsresult rv = aTransferable->FlavorsTransferableCanImport(getter_AddRefs(flavorList));
|
|
if (NS_FAILED(rv))
|
|
return NS_ERROR_FAILURE;
|
|
|
|
uint32_t flavorCount;
|
|
flavorList->Count(&flavorCount);
|
|
|
|
for (uint32_t i = 0; i < flavorCount; i++) {
|
|
nsCOMPtr<nsISupports> genericFlavor;
|
|
flavorList->GetElementAt(i, getter_AddRefs(genericFlavor));
|
|
nsCOMPtr<nsISupportsCString> currentFlavor(do_QueryInterface(genericFlavor));
|
|
if (!currentFlavor)
|
|
continue;
|
|
|
|
nsXPIDLCString flavorStr;
|
|
currentFlavor->ToString(getter_Copies(flavorStr)); // i has a flavr
|
|
|
|
// printf("looking for clipboard data of type %s\n", flavorStr.get());
|
|
|
|
NSString *pboardType = nil;
|
|
if (nsClipboard::IsStringType(flavorStr, &pboardType)) {
|
|
NSString* pString = [cocoaPasteboard stringForType:pboardType];
|
|
if (!pString)
|
|
continue;
|
|
|
|
NSData* stringData = [pString dataUsingEncoding:NSUnicodeStringEncoding];
|
|
unsigned int dataLength = [stringData length];
|
|
void* clipboardDataPtr = malloc(dataLength);
|
|
if (!clipboardDataPtr)
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
[stringData getBytes:clipboardDataPtr];
|
|
|
|
// The DOM only wants LF, so convert from MacOS line endings to DOM line endings.
|
|
int32_t signedDataLength = dataLength;
|
|
nsLinebreakHelpers::ConvertPlatformToDOMLinebreaks(flavorStr, &clipboardDataPtr, &signedDataLength);
|
|
dataLength = signedDataLength;
|
|
|
|
// skip BOM (Byte Order Mark to distinguish little or big endian)
|
|
char16_t* clipboardDataPtrNoBOM = (char16_t*)clipboardDataPtr;
|
|
if ((dataLength > 2) &&
|
|
((clipboardDataPtrNoBOM[0] == 0xFEFF) ||
|
|
(clipboardDataPtrNoBOM[0] == 0xFFFE))) {
|
|
dataLength -= sizeof(char16_t);
|
|
clipboardDataPtrNoBOM += 1;
|
|
}
|
|
|
|
nsCOMPtr<nsISupports> genericDataWrapper;
|
|
nsPrimitiveHelpers::CreatePrimitiveForData(flavorStr, clipboardDataPtrNoBOM, dataLength,
|
|
getter_AddRefs(genericDataWrapper));
|
|
aTransferable->SetTransferData(flavorStr, genericDataWrapper, dataLength);
|
|
free(clipboardDataPtr);
|
|
break;
|
|
}
|
|
else if (flavorStr.EqualsLiteral(kJPEGImageMime) ||
|
|
flavorStr.EqualsLiteral(kJPGImageMime) ||
|
|
flavorStr.EqualsLiteral(kPNGImageMime) ||
|
|
flavorStr.EqualsLiteral(kGIFImageMime)) {
|
|
// Figure out if there's data on the pasteboard we can grab (sanity check)
|
|
NSString *type = [cocoaPasteboard availableTypeFromArray:[NSArray arrayWithObjects:IMAGE_PASTEBOARD_TYPES]];
|
|
if (!type)
|
|
continue;
|
|
|
|
// Read data off the clipboard
|
|
NSData *pasteboardData = GetDataFromPasteboard(cocoaPasteboard, type);
|
|
if (!pasteboardData)
|
|
continue;
|
|
|
|
// Figure out what type we're converting to
|
|
CFStringRef outputType = NULL;
|
|
if (flavorStr.EqualsLiteral(kJPEGImageMime) ||
|
|
flavorStr.EqualsLiteral(kJPGImageMime))
|
|
outputType = CFSTR("public.jpeg");
|
|
else if (flavorStr.EqualsLiteral(kPNGImageMime))
|
|
outputType = CFSTR("public.png");
|
|
else if (flavorStr.EqualsLiteral(kGIFImageMime))
|
|
outputType = CFSTR("com.compuserve.gif");
|
|
else
|
|
continue;
|
|
|
|
// Use ImageIO to interpret the data on the clipboard and transcode.
|
|
// Note that ImageIO, like all CF APIs, allows NULLs to propagate freely
|
|
// and safely in most cases (like ObjC). A notable exception is CFRelease.
|
|
NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:
|
|
(NSNumber*)kCFBooleanTrue, kCGImageSourceShouldAllowFloat,
|
|
(type == NSTIFFPboardType ? @"public.tiff" : @"public.png"),
|
|
kCGImageSourceTypeIdentifierHint, nil];
|
|
|
|
CGImageSourceRef source = CGImageSourceCreateWithData((CFDataRef)pasteboardData,
|
|
(CFDictionaryRef)options);
|
|
NSMutableData *encodedData = [NSMutableData data];
|
|
CGImageDestinationRef dest = CGImageDestinationCreateWithData((CFMutableDataRef)encodedData,
|
|
outputType,
|
|
1, NULL);
|
|
CGImageDestinationAddImageFromSource(dest, source, 0, NULL);
|
|
bool successfullyConverted = CGImageDestinationFinalize(dest);
|
|
|
|
if (successfullyConverted) {
|
|
// Put the converted data in a form Gecko can understand
|
|
nsCOMPtr<nsIInputStream> byteStream;
|
|
NS_NewByteInputStream(getter_AddRefs(byteStream), (const char*)[encodedData bytes],
|
|
[encodedData length], NS_ASSIGNMENT_COPY);
|
|
|
|
aTransferable->SetTransferData(flavorStr, byteStream, sizeof(nsIInputStream*));
|
|
}
|
|
|
|
if (dest)
|
|
CFRelease(dest);
|
|
if (source)
|
|
CFRelease(source);
|
|
|
|
if (successfullyConverted)
|
|
break;
|
|
else
|
|
continue;
|
|
}
|
|
}
|
|
|
|
return NS_OK;
|
|
|
|
NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsClipboard::GetNativeClipboardData(nsITransferable* aTransferable, int32_t aWhichClipboard)
|
|
{
|
|
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
|
|
|
|
if ((aWhichClipboard != kGlobalClipboard && aWhichClipboard != kFindClipboard) || !aTransferable)
|
|
return NS_ERROR_FAILURE;
|
|
|
|
NSPasteboard* cocoaPasteboard;
|
|
if (aWhichClipboard == kFindClipboard) {
|
|
cocoaPasteboard = [NSPasteboard pasteboardWithName:NSFindPboard];
|
|
} else {
|
|
cocoaPasteboard = [NSPasteboard generalPasteboard];
|
|
}
|
|
if (!cocoaPasteboard)
|
|
return NS_ERROR_FAILURE;
|
|
|
|
// get flavor list that includes all acceptable flavors (including ones obtained through conversion)
|
|
nsCOMPtr<nsISupportsArray> flavorList;
|
|
nsresult rv = aTransferable->FlavorsTransferableCanImport(getter_AddRefs(flavorList));
|
|
if (NS_FAILED(rv))
|
|
return NS_ERROR_FAILURE;
|
|
|
|
uint32_t flavorCount;
|
|
flavorList->Count(&flavorCount);
|
|
|
|
// If we were the last ones to put something on the pasteboard, then just use the cached
|
|
// transferable. Otherwise clear it because it isn't relevant any more.
|
|
if (mCachedClipboard == aWhichClipboard &&
|
|
mChangeCount == [cocoaPasteboard changeCount]) {
|
|
if (mTransferable) {
|
|
for (uint32_t i = 0; i < flavorCount; i++) {
|
|
nsCOMPtr<nsISupports> genericFlavor;
|
|
flavorList->GetElementAt(i, getter_AddRefs(genericFlavor));
|
|
nsCOMPtr<nsISupportsCString> currentFlavor(do_QueryInterface(genericFlavor));
|
|
if (!currentFlavor)
|
|
continue;
|
|
|
|
nsXPIDLCString flavorStr;
|
|
currentFlavor->ToString(getter_Copies(flavorStr));
|
|
|
|
nsCOMPtr<nsISupports> dataSupports;
|
|
uint32_t dataSize = 0;
|
|
rv = mTransferable->GetTransferData(flavorStr, getter_AddRefs(dataSupports), &dataSize);
|
|
if (NS_SUCCEEDED(rv)) {
|
|
aTransferable->SetTransferData(flavorStr, dataSupports, dataSize);
|
|
return NS_OK; // maybe try to fill in more types? Is there a point?
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
nsBaseClipboard::EmptyClipboard(aWhichClipboard);
|
|
}
|
|
|
|
// at this point we can't satisfy the request from cache data so let's look
|
|
// for things other people put on the system clipboard
|
|
|
|
return nsClipboard::TransferableFromPasteboard(aTransferable, cocoaPasteboard);
|
|
|
|
NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
|
|
}
|
|
|
|
// returns true if we have *any* of the passed in flavors available for pasting
|
|
NS_IMETHODIMP
|
|
nsClipboard::HasDataMatchingFlavors(const char** aFlavorList, uint32_t aLength,
|
|
int32_t aWhichClipboard, bool* outResult)
|
|
{
|
|
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
|
|
|
|
*outResult = false;
|
|
|
|
if ((aWhichClipboard != kGlobalClipboard) || !aFlavorList)
|
|
return NS_OK;
|
|
|
|
// first see if we have data for this in our cached transferable
|
|
if (mTransferable) {
|
|
nsCOMPtr<nsISupportsArray> transferableFlavorList;
|
|
nsresult rv = mTransferable->FlavorsTransferableCanImport(getter_AddRefs(transferableFlavorList));
|
|
if (NS_SUCCEEDED(rv)) {
|
|
uint32_t transferableFlavorCount;
|
|
transferableFlavorList->Count(&transferableFlavorCount);
|
|
for (uint32_t j = 0; j < transferableFlavorCount; j++) {
|
|
nsCOMPtr<nsISupports> transferableFlavorSupports;
|
|
transferableFlavorList->GetElementAt(j, getter_AddRefs(transferableFlavorSupports));
|
|
nsCOMPtr<nsISupportsCString> currentTransferableFlavor(do_QueryInterface(transferableFlavorSupports));
|
|
if (!currentTransferableFlavor)
|
|
continue;
|
|
nsXPIDLCString transferableFlavorStr;
|
|
currentTransferableFlavor->ToString(getter_Copies(transferableFlavorStr));
|
|
|
|
for (uint32_t k = 0; k < aLength; k++) {
|
|
if (transferableFlavorStr.Equals(aFlavorList[k])) {
|
|
*outResult = true;
|
|
return NS_OK;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
NSPasteboard* generalPBoard = [NSPasteboard generalPasteboard];
|
|
|
|
for (uint32_t i = 0; i < aLength; i++) {
|
|
nsDependentCString mimeType(aFlavorList[i]);
|
|
NSString *pboardType = nil;
|
|
|
|
if (nsClipboard::IsStringType(mimeType, &pboardType)) {
|
|
NSString* availableType = [generalPBoard availableTypeFromArray:[NSArray arrayWithObject:pboardType]];
|
|
if (availableType && [availableType isEqualToString:pboardType]) {
|
|
*outResult = true;
|
|
break;
|
|
}
|
|
} else if (!strcmp(aFlavorList[i], kJPEGImageMime) ||
|
|
!strcmp(aFlavorList[i], kJPGImageMime) ||
|
|
!strcmp(aFlavorList[i], kPNGImageMime) ||
|
|
!strcmp(aFlavorList[i], kGIFImageMime)) {
|
|
NSString* availableType = [generalPBoard availableTypeFromArray:
|
|
[NSArray arrayWithObjects:IMAGE_PASTEBOARD_TYPES]];
|
|
if (availableType) {
|
|
*outResult = true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
return NS_OK;
|
|
|
|
NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsClipboard::SupportsFindClipboard(bool *_retval)
|
|
{
|
|
NS_ENSURE_ARG_POINTER(_retval);
|
|
*_retval = true;
|
|
return NS_OK;
|
|
}
|
|
|
|
// This function converts anything that other applications might understand into the system format
|
|
// and puts it into a dictionary which it returns.
|
|
// static
|
|
NSDictionary*
|
|
nsClipboard::PasteboardDictFromTransferable(nsITransferable* aTransferable)
|
|
{
|
|
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL;
|
|
|
|
if (!aTransferable)
|
|
return nil;
|
|
|
|
NSMutableDictionary* pasteboardOutputDict = [NSMutableDictionary dictionary];
|
|
|
|
nsCOMPtr<nsISupportsArray> flavorList;
|
|
nsresult rv = aTransferable->FlavorsTransferableCanExport(getter_AddRefs(flavorList));
|
|
if (NS_FAILED(rv))
|
|
return nil;
|
|
|
|
uint32_t flavorCount;
|
|
flavorList->Count(&flavorCount);
|
|
for (uint32_t i = 0; i < flavorCount; i++) {
|
|
nsCOMPtr<nsISupports> genericFlavor;
|
|
flavorList->GetElementAt(i, getter_AddRefs(genericFlavor));
|
|
nsCOMPtr<nsISupportsCString> currentFlavor(do_QueryInterface(genericFlavor));
|
|
if (!currentFlavor)
|
|
continue;
|
|
|
|
nsXPIDLCString flavorStr;
|
|
currentFlavor->ToString(getter_Copies(flavorStr));
|
|
|
|
PR_LOG(sCocoaLog, PR_LOG_ALWAYS, ("writing out clipboard data of type %s (%d)\n", flavorStr.get(), i));
|
|
|
|
NSString *pboardType = nil;
|
|
|
|
if (nsClipboard::IsStringType(flavorStr, &pboardType)) {
|
|
void* data = nullptr;
|
|
uint32_t dataSize = 0;
|
|
nsCOMPtr<nsISupports> genericDataWrapper;
|
|
rv = aTransferable->GetTransferData(flavorStr, getter_AddRefs(genericDataWrapper), &dataSize);
|
|
nsPrimitiveHelpers::CreateDataFromPrimitive(flavorStr, genericDataWrapper, &data, dataSize);
|
|
|
|
NSString* nativeString;
|
|
if (data)
|
|
nativeString = [NSString stringWithCharacters:(const unichar*)data length:(dataSize / sizeof(char16_t))];
|
|
else
|
|
nativeString = [NSString string];
|
|
|
|
// be nice to Carbon apps, normalize the receiver's contents using Form C.
|
|
nativeString = [nativeString precomposedStringWithCanonicalMapping];
|
|
|
|
[pasteboardOutputDict setObject:nativeString forKey:pboardType];
|
|
|
|
nsMemory::Free(data);
|
|
}
|
|
else if (flavorStr.EqualsLiteral(kPNGImageMime) || flavorStr.EqualsLiteral(kJPEGImageMime) ||
|
|
flavorStr.EqualsLiteral(kJPGImageMime) || flavorStr.EqualsLiteral(kGIFImageMime) ||
|
|
flavorStr.EqualsLiteral(kNativeImageMime)) {
|
|
uint32_t dataSize = 0;
|
|
nsCOMPtr<nsISupports> transferSupports;
|
|
aTransferable->GetTransferData(flavorStr, getter_AddRefs(transferSupports), &dataSize);
|
|
nsCOMPtr<nsISupportsInterfacePointer> ptrPrimitive(do_QueryInterface(transferSupports));
|
|
if (!ptrPrimitive)
|
|
continue;
|
|
|
|
nsCOMPtr<nsISupports> primitiveData;
|
|
ptrPrimitive->GetData(getter_AddRefs(primitiveData));
|
|
|
|
nsCOMPtr<imgIContainer> image(do_QueryInterface(primitiveData));
|
|
if (!image) {
|
|
NS_WARNING("Image isn't an imgIContainer in transferable");
|
|
continue;
|
|
}
|
|
|
|
RefPtr<SourceSurface> surface =
|
|
image->GetFrame(imgIContainer::FRAME_CURRENT,
|
|
imgIContainer::FLAG_SYNC_DECODE);
|
|
if (!surface) {
|
|
continue;
|
|
}
|
|
CGImageRef imageRef = NULL;
|
|
nsresult rv = nsCocoaUtils::CreateCGImageFromSurface(surface, &imageRef);
|
|
if (NS_FAILED(rv) || !imageRef) {
|
|
continue;
|
|
}
|
|
|
|
// Convert the CGImageRef to TIFF data.
|
|
CFMutableDataRef tiffData = CFDataCreateMutable(kCFAllocatorDefault, 0);
|
|
CGImageDestinationRef destRef = CGImageDestinationCreateWithData(tiffData,
|
|
CFSTR("public.tiff"),
|
|
1,
|
|
NULL);
|
|
CGImageDestinationAddImage(destRef, imageRef, NULL);
|
|
bool successfullyConverted = CGImageDestinationFinalize(destRef);
|
|
|
|
CGImageRelease(imageRef);
|
|
if (destRef)
|
|
CFRelease(destRef);
|
|
|
|
if (!successfullyConverted) {
|
|
if (tiffData)
|
|
CFRelease(tiffData);
|
|
continue;
|
|
}
|
|
|
|
[pasteboardOutputDict setObject:(NSMutableData*)tiffData forKey:NSTIFFPboardType];
|
|
if (tiffData)
|
|
CFRelease(tiffData);
|
|
}
|
|
else if (flavorStr.EqualsLiteral(kFileMime)) {
|
|
uint32_t len = 0;
|
|
nsCOMPtr<nsISupports> genericFile;
|
|
rv = aTransferable->GetTransferData(flavorStr, getter_AddRefs(genericFile), &len);
|
|
if (NS_FAILED(rv)) {
|
|
continue;
|
|
}
|
|
|
|
nsCOMPtr<nsIFile> file(do_QueryInterface(genericFile));
|
|
if (!file) {
|
|
nsCOMPtr<nsISupportsInterfacePointer> ptr(do_QueryInterface(genericFile));
|
|
|
|
if (ptr) {
|
|
ptr->GetData(getter_AddRefs(genericFile));
|
|
file = do_QueryInterface(genericFile);
|
|
}
|
|
}
|
|
|
|
if (!file) {
|
|
continue;
|
|
}
|
|
|
|
nsAutoString fileURI;
|
|
rv = file->GetPath(fileURI);
|
|
if (NS_FAILED(rv)) {
|
|
continue;
|
|
}
|
|
|
|
NSString* str = nsCocoaUtils::ToNSString(fileURI);
|
|
NSArray* fileList = [NSArray arrayWithObjects:str, nil];
|
|
[pasteboardOutputDict setObject:fileList forKey:NSFilenamesPboardType];
|
|
}
|
|
else if (flavorStr.EqualsLiteral(kFilePromiseMime)) {
|
|
[pasteboardOutputDict setObject:[NSArray arrayWithObject:@""] forKey:NSFilesPromisePboardType];
|
|
}
|
|
else if (flavorStr.EqualsLiteral(kURLMime)) {
|
|
uint32_t len = 0;
|
|
nsCOMPtr<nsISupports> genericURL;
|
|
rv = aTransferable->GetTransferData(flavorStr, getter_AddRefs(genericURL), &len);
|
|
nsCOMPtr<nsISupportsString> urlObject(do_QueryInterface(genericURL));
|
|
|
|
nsAutoString url;
|
|
urlObject->GetData(url);
|
|
|
|
// A newline embedded in the URL means that the form is actually URL + title.
|
|
int32_t newlinePos = url.FindChar(char16_t('\n'));
|
|
if (newlinePos >= 0) {
|
|
url.Truncate(newlinePos);
|
|
|
|
nsAutoString urlTitle;
|
|
urlObject->GetData(urlTitle);
|
|
urlTitle.Mid(urlTitle, newlinePos + 1, len - (newlinePos + 1));
|
|
|
|
NSString *nativeTitle = [[NSString alloc] initWithCharacters:reinterpret_cast<const unichar*>(urlTitle.get())
|
|
length:urlTitle.Length()];
|
|
// be nice to Carbon apps, normalize the receiver's contents using Form C.
|
|
[pasteboardOutputDict setObject:[nativeTitle precomposedStringWithCanonicalMapping] forKey:kCorePboardType_urln];
|
|
// Also put the title out as 'urld', since some recipients will look for that.
|
|
[pasteboardOutputDict setObject:[nativeTitle precomposedStringWithCanonicalMapping] forKey:kCorePboardType_urld];
|
|
[nativeTitle release];
|
|
}
|
|
|
|
// The Finder doesn't like getting random binary data aka
|
|
// Unicode, so change it into an escaped URL containing only
|
|
// ASCII.
|
|
nsAutoCString utf8Data = NS_ConvertUTF16toUTF8(url.get(), url.Length());
|
|
nsAutoCString escData;
|
|
NS_EscapeURL(utf8Data.get(), utf8Data.Length(), esc_OnlyNonASCII|esc_AlwaysCopy, escData);
|
|
|
|
// printf("Escaped url is %s, length %d\n", escData.get(), escData.Length());
|
|
|
|
NSString *nativeURL = [NSString stringWithUTF8String:escData.get()];
|
|
[pasteboardOutputDict setObject:nativeURL forKey:kCorePboardType_url];
|
|
}
|
|
// If it wasn't a type that we recognize as exportable we don't put it on the system
|
|
// clipboard. We'll just access it from our cached transferable when we need it.
|
|
}
|
|
|
|
return pasteboardOutputDict;
|
|
|
|
NS_OBJC_END_TRY_ABORT_BLOCK_NIL;
|
|
}
|
|
|
|
bool nsClipboard::IsStringType(const nsCString& aMIMEType, NSString** aPasteboardType)
|
|
{
|
|
if (aMIMEType.EqualsLiteral(kUnicodeMime) ||
|
|
aMIMEType.EqualsLiteral(kHTMLMime)) {
|
|
if (aMIMEType.EqualsLiteral(kUnicodeMime))
|
|
*aPasteboardType = NSStringPboardType;
|
|
else
|
|
*aPasteboardType = NSHTMLPboardType;
|
|
return true;
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
NSString* nsClipboard::WrapHtmlForSystemPasteboard(NSString* aString)
|
|
{
|
|
NSString* wrapped =
|
|
[NSString stringWithFormat:
|
|
@"<html>"
|
|
"<head>"
|
|
"<meta http-equiv=\"content-type\" content=\"text/html; charset=utf-8\">"
|
|
"</head>"
|
|
"<body>"
|
|
"%@"
|
|
"</body>"
|
|
"</html>", aString];
|
|
return wrapped;
|
|
}
|