2007-03-22 10:30:00 -07:00
|
|
|
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
|
|
/* ***** BEGIN LICENSE BLOCK *****
|
|
|
|
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
|
|
|
*
|
|
|
|
* The contents of this file are subject to the Mozilla Public License Version
|
|
|
|
* 1.1 (the "License"); you may not use this file except in compliance with
|
|
|
|
* the License. You may obtain a copy of the License at
|
|
|
|
* http://www.mozilla.org/MPL/
|
|
|
|
*
|
|
|
|
* Software distributed under the License is distributed on an "AS IS" basis,
|
|
|
|
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
|
|
|
* for the specific language governing rights and limitations under the
|
|
|
|
* License.
|
|
|
|
*
|
|
|
|
* The Original Code is mozilla.org code.
|
|
|
|
*
|
|
|
|
* The Initial Developer of the Original Code is
|
|
|
|
* Mozilla Corporation.
|
|
|
|
* Portions created by the Initial Developer are Copyright (C) 2006
|
|
|
|
* the Initial Developer. All Rights Reserved.
|
|
|
|
*
|
|
|
|
* Contributor(s):
|
|
|
|
* Josh Aas <josh@mozilla.com>
|
|
|
|
*
|
|
|
|
* Alternatively, the contents of this file may be used under the terms of
|
|
|
|
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
|
|
|
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
|
|
|
* in which case the provisions of the GPL or the LGPL are applicable instead
|
|
|
|
* of those above. If you wish to allow use of your version of this file only
|
|
|
|
* under the terms of either the GPL or the LGPL, and not to allow others to
|
|
|
|
* use your version of this file under the terms of the MPL, indicate your
|
|
|
|
* decision by deleting the provisions above and replace them with the notice
|
|
|
|
* and other provisions required by the GPL or the LGPL. If you do not delete
|
|
|
|
* the provisions above, a recipient may use your version of this file under
|
|
|
|
* the terms of any one of the MPL, the GPL or the LGPL.
|
|
|
|
*
|
|
|
|
* ***** END LICENSE BLOCK ***** */
|
|
|
|
|
|
|
|
#include "nsCOMPtr.h"
|
|
|
|
#include "nsClipboard.h"
|
|
|
|
#include "nsString.h"
|
|
|
|
#include "nsISupportsPrimitives.h"
|
|
|
|
#include "nsXPIDLString.h"
|
|
|
|
#include "nsPrimitiveHelpers.h"
|
|
|
|
#include "nsMemory.h"
|
|
|
|
#include "nsIImage.h"
|
2007-06-26 22:26:18 -07:00
|
|
|
#include "nsILocalFile.h"
|
2007-09-17 11:02:50 -07:00
|
|
|
#include "nsStringStream.h"
|
|
|
|
|
|
|
|
// Screenshots use the (undocumented) png pasteboard type.
|
|
|
|
#define IMAGE_PASTEBOARD_TYPES NSTIFFPboardType, @"Apple PNG pasteboard type", nil
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2007-09-04 23:58:16 -07:00
|
|
|
#ifdef MOZ_LOGGING
|
|
|
|
#define FORCE_PR_LOG
|
|
|
|
#endif
|
|
|
|
#include "prlog.h"
|
|
|
|
|
|
|
|
#ifdef PR_LOGGING
|
|
|
|
extern PRLogModuleInfo* sCocoaLog;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
nsClipboard::nsClipboard() : nsBaseClipboard()
|
|
|
|
{
|
2007-07-03 00:16:19 -07:00
|
|
|
mChangeCount = 0;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
nsClipboard::~nsClipboard()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsClipboard::SetNativeClipboardData(PRInt32 aWhichClipboard)
|
|
|
|
{
|
|
|
|
if ((aWhichClipboard != kGlobalClipboard) || !mTransferable)
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
|
|
|
|
mIgnoreEmptyNotification = PR_TRUE;
|
|
|
|
|
2007-06-26 22:26:18 -07:00
|
|
|
NSDictionary* pasteboardOutputDict = PasteboardDictFromTransferable(mTransferable);
|
|
|
|
if (!pasteboardOutputDict)
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
|
|
|
|
// write everything out to the general pasteboard
|
|
|
|
unsigned int outputCount = [pasteboardOutputDict count];
|
|
|
|
NSArray* outputKeys = [pasteboardOutputDict allKeys];
|
|
|
|
NSPasteboard* generalPBoard = [NSPasteboard generalPasteboard];
|
|
|
|
[generalPBoard declareTypes:outputKeys owner:nil];
|
|
|
|
for (unsigned int i = 0; i < outputCount; i++) {
|
|
|
|
NSString* currentKey = [outputKeys objectAtIndex:i];
|
|
|
|
id currentValue = [pasteboardOutputDict valueForKey:currentKey];
|
|
|
|
if (currentKey == NSStringPboardType)
|
|
|
|
[generalPBoard setString:currentValue forType:currentKey];
|
|
|
|
else
|
|
|
|
[generalPBoard setData:currentValue forType:currentKey];
|
|
|
|
}
|
|
|
|
|
2007-07-03 00:16:19 -07:00
|
|
|
mChangeCount = [generalPBoard changeCount];
|
|
|
|
|
2007-06-26 22:26:18 -07:00
|
|
|
mIgnoreEmptyNotification = PR_FALSE;
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsClipboard::GetNativeClipboardData(nsITransferable* aTransferable, PRInt32 aWhichClipboard)
|
2007-07-03 00:16:19 -07:00
|
|
|
{
|
2007-06-26 22:26:18 -07:00
|
|
|
if ((aWhichClipboard != kGlobalClipboard) || !aTransferable)
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
|
2007-07-03 00:16:19 -07:00
|
|
|
NSPasteboard* 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;
|
|
|
|
|
|
|
|
PRUint32 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 (mChangeCount == [cocoaPasteboard changeCount]) {
|
|
|
|
if (mTransferable) {
|
|
|
|
for (PRUint32 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;
|
|
|
|
PRUint32 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(kGlobalClipboard);
|
|
|
|
}
|
|
|
|
|
|
|
|
// 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
|
|
|
|
|
|
|
|
for (PRUint32 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());
|
|
|
|
|
|
|
|
if (flavorStr.EqualsLiteral(kUnicodeMime)) {
|
|
|
|
NSString* pString = [cocoaPasteboard stringForType:NSStringPboardType];
|
|
|
|
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.
|
|
|
|
PRInt32 signedDataLength = dataLength;
|
|
|
|
nsLinebreakHelpers::ConvertPlatformToDOMLinebreaks(flavorStr, &clipboardDataPtr, &signedDataLength);
|
|
|
|
dataLength = signedDataLength;
|
|
|
|
|
|
|
|
// skip BOM (Byte Order Mark to distinguish little or big endian)
|
|
|
|
PRUnichar* clipboardDataPtrNoBOM = (PRUnichar*)clipboardDataPtr;
|
|
|
|
if ((dataLength > 2) &&
|
|
|
|
((clipboardDataPtrNoBOM[0] == 0xFEFF) ||
|
|
|
|
(clipboardDataPtrNoBOM[0] == 0xFFFE))) {
|
|
|
|
dataLength -= sizeof(PRUnichar);
|
|
|
|
clipboardDataPtrNoBOM += 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsCOMPtr<nsISupports> genericDataWrapper;
|
|
|
|
nsPrimitiveHelpers::CreatePrimitiveForData(flavorStr, clipboardDataPtrNoBOM, dataLength,
|
|
|
|
getter_AddRefs(genericDataWrapper));
|
|
|
|
aTransferable->SetTransferData(flavorStr, genericDataWrapper, dataLength);
|
|
|
|
free(clipboardDataPtr);
|
|
|
|
break;
|
|
|
|
}
|
2007-09-17 11:02:50 -07:00
|
|
|
else if (flavorStr.EqualsLiteral(kJPEGImageMime) ||
|
|
|
|
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;
|
2007-07-03 00:16:19 -07:00
|
|
|
|
2007-09-17 11:02:50 -07:00
|
|
|
// Read data off the clipboard, make sure to catch any exceptions (timeouts)
|
|
|
|
// XXX should convert to @try/@catch someday?
|
|
|
|
NSData *pasteboardData = nil;
|
|
|
|
NS_DURING
|
|
|
|
pasteboardData = [cocoaPasteboard dataForType:type];
|
|
|
|
NS_HANDLER
|
|
|
|
NS_ASSERTION(0, "Exception raised while getting data from the pasteboard.");
|
|
|
|
NS_ENDHANDLER
|
|
|
|
if (!pasteboardData)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
// Figure out what type we're converting to
|
|
|
|
CFStringRef outputType = NULL;
|
|
|
|
if (flavorStr.EqualsLiteral(kJPEGImageMime))
|
|
|
|
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);
|
|
|
|
PRBool 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;
|
2007-07-03 00:16:19 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return NS_OK;
|
2007-06-26 22:26:18 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2007-07-03 16:13:28 -07:00
|
|
|
// returns true if we have *any* of the passed in flavors available for pasting
|
2007-06-26 22:26:18 -07:00
|
|
|
NS_IMETHODIMP
|
|
|
|
nsClipboard::HasDataMatchingFlavors(nsISupportsArray* aFlavorList, PRInt32 aWhichClipboard, PRBool* outResult)
|
|
|
|
{
|
|
|
|
*outResult = PR_FALSE;
|
|
|
|
|
|
|
|
if ((aWhichClipboard != kGlobalClipboard) || !aFlavorList)
|
|
|
|
return NS_OK;
|
|
|
|
|
2007-07-03 16:13:28 -07:00
|
|
|
// 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)) {
|
|
|
|
PRUint32 transferableFlavorCount;
|
|
|
|
transferableFlavorList->Count(&transferableFlavorCount);
|
|
|
|
for (PRUint32 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));
|
|
|
|
|
|
|
|
PRUint32 passedFlavorCount;
|
|
|
|
aFlavorList->Count(&passedFlavorCount);
|
|
|
|
for (PRUint32 k = 0; k < passedFlavorCount; k++) {
|
|
|
|
nsCOMPtr<nsISupports> passedFlavorSupports;
|
2007-07-05 17:36:49 -07:00
|
|
|
aFlavorList->GetElementAt(k, getter_AddRefs(passedFlavorSupports));
|
2007-07-03 16:13:28 -07:00
|
|
|
nsCOMPtr<nsISupportsCString> currentPassedFlavor(do_QueryInterface(passedFlavorSupports));
|
|
|
|
if (!currentPassedFlavor)
|
|
|
|
continue;
|
|
|
|
nsXPIDLCString passedFlavorStr;
|
|
|
|
currentPassedFlavor->ToString(getter_Copies(passedFlavorStr));
|
|
|
|
if (passedFlavorStr.Equals(transferableFlavorStr)) {
|
|
|
|
*outResult = PR_TRUE;
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-06-26 22:26:18 -07:00
|
|
|
NSPasteboard* generalPBoard = [NSPasteboard generalPasteboard];
|
|
|
|
|
2007-07-03 16:13:28 -07:00
|
|
|
PRUint32 passedFlavorCount;
|
|
|
|
aFlavorList->Count(&passedFlavorCount);
|
|
|
|
for (PRUint32 i = 0; i < passedFlavorCount; i++) {
|
|
|
|
nsCOMPtr<nsISupports> passedFlavorSupports;
|
|
|
|
aFlavorList->GetElementAt(i, getter_AddRefs(passedFlavorSupports));
|
|
|
|
nsCOMPtr<nsISupportsCString> flavorWrapper(do_QueryInterface(passedFlavorSupports));
|
2007-06-26 22:26:18 -07:00
|
|
|
if (flavorWrapper) {
|
|
|
|
nsXPIDLCString flavorStr;
|
|
|
|
flavorWrapper->ToString(getter_Copies(flavorStr));
|
2007-07-03 00:16:19 -07:00
|
|
|
if (flavorStr.EqualsLiteral(kUnicodeMime)) {
|
2007-06-26 22:26:18 -07:00
|
|
|
NSString* availableType = [generalPBoard availableTypeFromArray:[NSArray arrayWithObject:NSStringPboardType]];
|
|
|
|
if (availableType && [availableType isEqualToString:NSStringPboardType]) {
|
|
|
|
*outResult = PR_TRUE;
|
|
|
|
break;
|
|
|
|
}
|
2007-09-17 11:02:50 -07:00
|
|
|
} else if (flavorStr.EqualsLiteral(kJPEGImageMime) ||
|
|
|
|
flavorStr.EqualsLiteral(kPNGImageMime) ||
|
|
|
|
flavorStr.EqualsLiteral(kGIFImageMime)) {
|
|
|
|
NSString* availableType = [generalPBoard availableTypeFromArray:
|
|
|
|
[NSArray arrayWithObjects:IMAGE_PASTEBOARD_TYPES]];
|
|
|
|
if (availableType) {
|
|
|
|
*outResult = PR_TRUE;
|
|
|
|
break;
|
|
|
|
}
|
2007-06-26 22:26:18 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2007-07-03 00:16:19 -07:00
|
|
|
|
|
|
|
// This function converts anything that other applications might understand into the system format
|
|
|
|
// and puts it into a dictionary which it returns.
|
2007-06-26 22:26:18 -07:00
|
|
|
// static
|
|
|
|
NSDictionary*
|
|
|
|
nsClipboard::PasteboardDictFromTransferable(nsITransferable* aTransferable)
|
|
|
|
{
|
|
|
|
if (!aTransferable)
|
|
|
|
return nil;
|
|
|
|
|
|
|
|
NSMutableDictionary* pasteboardOutputDict = [NSMutableDictionary dictionary];
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
nsCOMPtr<nsISupportsArray> flavorList;
|
2007-06-26 22:26:18 -07:00
|
|
|
nsresult rv = aTransferable->FlavorsTransferableCanExport(getter_AddRefs(flavorList));
|
2007-03-22 10:30:00 -07:00
|
|
|
if (NS_FAILED(rv))
|
2007-06-26 22:26:18 -07:00
|
|
|
return nil;
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
PRUint32 flavorCount;
|
|
|
|
flavorList->Count(&flavorCount);
|
|
|
|
for (PRUint32 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));
|
|
|
|
|
2007-07-16 19:24:05 -07:00
|
|
|
PR_LOG(sCocoaLog, PR_LOG_ALWAYS, ("writing out clipboard data of type %s (%d)\n", flavorStr.get(), i));
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2007-07-03 00:16:19 -07:00
|
|
|
if (flavorStr.EqualsLiteral(kUnicodeMime)) {
|
|
|
|
void* data = nsnull;
|
|
|
|
PRUint32 dataSize = 0;
|
|
|
|
nsCOMPtr<nsISupports> genericDataWrapper;
|
|
|
|
rv = aTransferable->GetTransferData(flavorStr, getter_AddRefs(genericDataWrapper), &dataSize);
|
|
|
|
nsPrimitiveHelpers::CreateDataFromPrimitive(flavorStr, genericDataWrapper, &data, dataSize);
|
|
|
|
|
|
|
|
NSString* nativeString = [NSString stringWithCharacters:(const unichar*)data length:(dataSize / sizeof(PRUnichar))];
|
|
|
|
// be nice to Carbon apps, normalize the receiver's contents using Form C.
|
|
|
|
nativeString = [nativeString precomposedStringWithCanonicalMapping];
|
|
|
|
[pasteboardOutputDict setObject:nativeString forKey:NSStringPboardType];
|
|
|
|
|
|
|
|
nsMemory::Free(data);
|
|
|
|
}
|
|
|
|
else if (flavorStr.EqualsLiteral(kPNGImageMime) || flavorStr.EqualsLiteral(kJPEGImageMime) ||
|
|
|
|
flavorStr.EqualsLiteral(kGIFImageMime) || flavorStr.EqualsLiteral(kNativeImageMime)) {
|
2007-03-22 10:30:00 -07:00
|
|
|
PRUint32 dataSize = 0;
|
|
|
|
nsCOMPtr<nsISupports> transferSupports;
|
2007-06-26 22:26:18 -07:00
|
|
|
aTransferable->GetTransferData(flavorStr, getter_AddRefs(transferSupports), &dataSize);
|
2007-03-22 10:30:00 -07:00
|
|
|
nsCOMPtr<nsISupportsInterfacePointer> ptrPrimitive(do_QueryInterface(transferSupports));
|
|
|
|
if (!ptrPrimitive)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
nsCOMPtr<nsISupports> primitiveData;
|
|
|
|
ptrPrimitive->GetData(getter_AddRefs(primitiveData));
|
|
|
|
|
|
|
|
nsCOMPtr<nsIImage> image(do_QueryInterface(primitiveData));
|
|
|
|
if (!image) {
|
|
|
|
NS_WARNING("Image isn't an nsIImage in transferable");
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (NS_FAILED(image->LockImagePixels(PR_FALSE)))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
PRInt32 height = image->GetHeight();
|
|
|
|
PRInt32 stride = image->GetLineStride();
|
|
|
|
PRInt32 width = image->GetWidth();
|
|
|
|
if ((stride % 4 != 0) || (height < 1) || (width < 1))
|
|
|
|
continue;
|
|
|
|
|
2007-08-29 19:10:32 -07:00
|
|
|
// Create a CGImageRef with the bits from the image, taking into account
|
|
|
|
// the alpha ordering and endianness of the machine so we don't have to
|
|
|
|
// touch the bits ourselves.
|
|
|
|
CGDataProviderRef dataProvider = CGDataProviderCreateWithData(NULL,
|
|
|
|
image->GetBits(),
|
|
|
|
stride * height,
|
|
|
|
NULL);
|
|
|
|
CGColorSpaceRef colorSpace = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB);
|
|
|
|
CGImageRef imageRef = CGImageCreate(width,
|
|
|
|
height,
|
|
|
|
8,
|
|
|
|
32,
|
|
|
|
stride,
|
|
|
|
colorSpace,
|
|
|
|
kCGBitmapByteOrder32Host | kCGImageAlphaFirst,
|
|
|
|
dataProvider,
|
|
|
|
NULL,
|
|
|
|
0,
|
|
|
|
kCGRenderingIntentDefault);
|
2007-09-17 11:02:50 -07:00
|
|
|
CGColorSpaceRelease(colorSpace);
|
2007-08-29 19:10:32 -07:00
|
|
|
CGDataProviderRelease(dataProvider);
|
|
|
|
|
|
|
|
// Convert the CGImageRef to TIFF data.
|
|
|
|
CFMutableDataRef tiffData = CFDataCreateMutable(kCFAllocatorDefault, 0);
|
|
|
|
CGImageDestinationRef destRef = CGImageDestinationCreateWithData(tiffData,
|
2007-09-17 11:02:50 -07:00
|
|
|
CFSTR("public.tiff"),
|
2007-08-29 19:10:32 -07:00
|
|
|
1,
|
2007-09-17 11:02:50 -07:00
|
|
|
NULL);
|
|
|
|
CGImageDestinationAddImage(destRef, imageRef, NULL);
|
|
|
|
PRBool successfullyConverted = CGImageDestinationFinalize(destRef);
|
2007-08-29 19:10:32 -07:00
|
|
|
|
|
|
|
CGImageRelease(imageRef);
|
2007-09-17 11:02:50 -07:00
|
|
|
if (destRef)
|
|
|
|
CFRelease(destRef);
|
2007-08-29 19:10:32 -07:00
|
|
|
|
2007-09-17 11:02:50 -07:00
|
|
|
if (NS_FAILED(image->UnlockImagePixels(PR_FALSE)) || !successfullyConverted) {
|
|
|
|
if (tiffData)
|
|
|
|
CFRelease(tiffData);
|
2007-03-22 10:30:00 -07:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2007-08-29 19:10:32 -07:00
|
|
|
[pasteboardOutputDict setObject:(NSMutableData*)tiffData forKey:NSTIFFPboardType];
|
2007-09-17 11:02:50 -07:00
|
|
|
if (tiffData)
|
|
|
|
CFRelease(tiffData);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
2007-07-19 11:09:43 -07:00
|
|
|
else if (flavorStr.EqualsLiteral(kFilePromiseMime)) {
|
|
|
|
[pasteboardOutputDict setObject:[NSArray arrayWithObject:@""] forKey:NSFilesPromisePboardType];
|
|
|
|
}
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2007-07-03 00:16:19 -07:00
|
|
|
// 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.
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2007-07-03 00:16:19 -07:00
|
|
|
return pasteboardOutputDict;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|