715 lines
28 KiB
C++
715 lines
28 KiB
C++
/* -*- 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
|
|
* Netscape Communications Corporation.
|
|
* Portions created by the Initial Developer are Copyright (C) 1998
|
|
* the Initial Developer. All Rights Reserved.
|
|
*
|
|
* Contributor(s):
|
|
*
|
|
* 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 ***** */
|
|
|
|
//
|
|
// Mike Pinkerton
|
|
// Netscape Communications
|
|
//
|
|
// See header file for details.
|
|
//
|
|
// Remaining Work:
|
|
// * only convert data to clipboard on an app switch.
|
|
//
|
|
|
|
#include "nsCOMPtr.h"
|
|
#include "nsClipboard.h"
|
|
|
|
#include "nsIClipboardOwner.h"
|
|
#include "nsString.h"
|
|
#include "nsIFormatConverter.h"
|
|
#include "nsMimeMapper.h"
|
|
|
|
#include "nsIComponentManager.h"
|
|
#include "nsXPCOM.h"
|
|
#include "nsISupportsPrimitives.h"
|
|
#include "nsXPIDLString.h"
|
|
#include "nsPrimitiveHelpers.h"
|
|
#ifndef MOZ_CAIRO_GFX
|
|
#include "nsIImageMac.h"
|
|
#endif
|
|
#include "nsMemory.h"
|
|
#include "nsMacNativeUnicodeConverter.h"
|
|
#include "nsICharsetConverterManager.h"
|
|
#include "nsCRT.h"
|
|
#include "nsStylClipboardUtils.h"
|
|
#include "nsLinebreakConverter.h"
|
|
#include "nsAutoPtr.h"
|
|
#include "nsIServiceManager.h"
|
|
#include "nsIMacUtils.h"
|
|
|
|
#include <Scrap.h>
|
|
#include <Script.h>
|
|
#include <TextEdit.h>
|
|
|
|
static const PRUint32 kPrivateFlavorMask = 0xffff0000;
|
|
static const PRUint32 kPrivateFlavorTag = 'MZ..' & kPrivateFlavorMask;
|
|
|
|
|
|
|
|
//
|
|
// nsClipboard constructor
|
|
//
|
|
nsClipboard::nsClipboard() : nsBaseClipboard()
|
|
{
|
|
}
|
|
|
|
//
|
|
// nsClipboard destructor
|
|
//
|
|
nsClipboard::~nsClipboard()
|
|
{
|
|
}
|
|
|
|
|
|
//
|
|
// SetNativeClipboardData
|
|
//
|
|
// Take data off the transferrable and put it on the clipboard in as many formats
|
|
// as are registered.
|
|
//
|
|
// NOTE: This code could all live in a shutdown observer and this could be a NOOP.
|
|
// If speed and large data sizes are an issue, we should move that code there and only
|
|
// do it on an app switch.
|
|
//
|
|
NS_IMETHODIMP
|
|
nsClipboard :: SetNativeClipboardData ( PRInt32 aWhichClipboard )
|
|
{
|
|
if ( aWhichClipboard != kGlobalClipboard )
|
|
return NS_ERROR_FAILURE;
|
|
|
|
nsresult errCode = NS_OK;
|
|
|
|
mIgnoreEmptyNotification = PR_TRUE;
|
|
|
|
// make sure we have a good transferable
|
|
if ( !mTransferable )
|
|
return NS_ERROR_INVALID_ARG;
|
|
|
|
nsMimeMapperMac theMapper;
|
|
|
|
::ClearCurrentScrap();
|
|
|
|
// get flavor list that includes all flavors that can be written (including ones
|
|
// obtained through conversion)
|
|
nsCOMPtr<nsISupportsArray> flavorList;
|
|
errCode = mTransferable->FlavorsTransferableCanExport ( getter_AddRefs(flavorList) );
|
|
if ( NS_FAILED(errCode) )
|
|
return NS_ERROR_FAILURE;
|
|
|
|
// For each flavor present (either directly in the transferable or that its
|
|
// converter knows about) put it on the clipboard. Luckily, GetTransferData()
|
|
// handles conversions for us, so we really don't need to know if a conversion
|
|
// is required or not.
|
|
PRUint32 cnt;
|
|
flavorList->Count(&cnt);
|
|
for ( PRUint32 i = 0; i < cnt; ++i ) {
|
|
nsCOMPtr<nsISupports> genericFlavor;
|
|
flavorList->GetElementAt ( i, getter_AddRefs(genericFlavor) );
|
|
nsCOMPtr<nsISupportsCString> currentFlavor ( do_QueryInterface(genericFlavor) );
|
|
if ( currentFlavor ) {
|
|
nsXPIDLCString flavorStr;
|
|
currentFlavor->ToString( getter_Copies(flavorStr) );
|
|
|
|
// find MacOS flavor
|
|
ResType macOSFlavor = theMapper.MapMimeTypeToMacOSType(flavorStr);
|
|
|
|
// get data. This takes converters into account. Different things happen for
|
|
// different flavors, so do some special processing.
|
|
void* data = nsnull;
|
|
PRUint32 dataSize = 0;
|
|
if ( strcmp(flavorStr,kUnicodeMime) == 0 ) {
|
|
// we have unicode, put it on first as unicode
|
|
nsCOMPtr<nsISupports> genericDataWrapper;
|
|
errCode = mTransferable->GetTransferData ( flavorStr, getter_AddRefs(genericDataWrapper), &dataSize );
|
|
nsPrimitiveHelpers::CreateDataFromPrimitive ( flavorStr, genericDataWrapper, &data, dataSize );
|
|
|
|
// Convert unix to mac linebreaks, since mac linebreaks are required for clipboard compatibility.
|
|
|
|
PRUnichar* castedData = NS_REINTERPRET_CAST(PRUnichar*, data);
|
|
PRUnichar* linebreakConvertedUnicode = castedData;
|
|
nsLinebreakConverter::ConvertUnicharLineBreaksInSitu(&linebreakConvertedUnicode,
|
|
nsLinebreakConverter::eLinebreakUnix,
|
|
nsLinebreakConverter::eLinebreakMac,
|
|
dataSize / sizeof(PRUnichar), nsnull);
|
|
|
|
errCode = PutOnClipboard ( macOSFlavor, data, dataSize );
|
|
if ( NS_SUCCEEDED(errCode) ) {
|
|
// we also need to put it on as 'TEXT' after doing the conversion to the platform charset.
|
|
char* plainTextData = nsnull;
|
|
PRInt32 plainTextLen = 0;
|
|
errCode = nsPrimitiveHelpers::ConvertUnicodeToPlatformPlainText ( linebreakConvertedUnicode, dataSize / 2, &plainTextData, &plainTextLen );
|
|
|
|
ScriptCodeRun *scriptCodeRuns = nsnull;
|
|
PRInt32 scriptRunOutLen;
|
|
|
|
// if characters are not mapped from Unicode then try native API to convert to
|
|
// available script
|
|
if (errCode == NS_ERROR_UENC_NOMAPPING) {
|
|
if (plainTextData) {
|
|
nsMemory::Free(plainTextData);
|
|
plainTextData = nsnull;
|
|
}
|
|
errCode = nsMacNativeUnicodeConverter::ConvertUnicodetoScript(linebreakConvertedUnicode,
|
|
dataSize / 2,
|
|
&plainTextData,
|
|
&plainTextLen,
|
|
&scriptCodeRuns,
|
|
&scriptRunOutLen);
|
|
}
|
|
else if (NS_SUCCEEDED(errCode)) {
|
|
// create a single run with the default system script
|
|
scriptCodeRuns = NS_REINTERPRET_CAST(ScriptCodeRun*,
|
|
nsMemory::Alloc(sizeof(ScriptCodeRun)));
|
|
if (scriptCodeRuns) {
|
|
scriptCodeRuns[0].offset = 0;
|
|
scriptCodeRuns[0].script = (ScriptCode) ::GetScriptManagerVariable(smSysScript);
|
|
scriptRunOutLen = 1;
|
|
}
|
|
}
|
|
|
|
if ( NS_SUCCEEDED(errCode) && plainTextData ) {
|
|
errCode = PutOnClipboard ( 'TEXT', plainTextData, plainTextLen );
|
|
nsMemory::Free ( plainTextData );
|
|
|
|
// create 'styl' from the script runs
|
|
if (NS_SUCCEEDED(errCode) && scriptCodeRuns) {
|
|
char *stylData;
|
|
PRInt32 stylLen;
|
|
errCode = CreateStylFromScriptRuns(scriptCodeRuns,
|
|
scriptRunOutLen,
|
|
&stylData,
|
|
&stylLen);
|
|
if (NS_SUCCEEDED(errCode)) {
|
|
errCode = PutOnClipboard ('styl', stylData, stylLen);
|
|
nsMemory::Free(stylData);
|
|
}
|
|
}
|
|
}
|
|
if (scriptCodeRuns)
|
|
nsMemory::Free(scriptCodeRuns);
|
|
}
|
|
|
|
// ConvertUnicharLineBreaksInSitu may have allocated a new buffer
|
|
// (although unlikely when converting from '\n' to '\r').
|
|
if (linebreakConvertedUnicode != castedData)
|
|
nsMemory::Free(linebreakConvertedUnicode);
|
|
} // if unicode
|
|
else if ( strcmp(flavorStr, kPNGImageMime) == 0 || strcmp(flavorStr, kJPEGImageMime) == 0 ||
|
|
strcmp(flavorStr, kGIFImageMime) == 0 || strcmp(flavorStr, kNativeImageMime) == 0 ) {
|
|
// we have an image, which is in the transferable as an nsIImage. Convert it
|
|
// to PICT (PicHandle) and put those bits on the clipboard. The actual size
|
|
// of the picture is the size of the handle, not sizeof(Picture).
|
|
nsCOMPtr<nsISupports> transferSupports;
|
|
errCode = mTransferable->GetTransferData ( flavorStr, getter_AddRefs(transferSupports), &dataSize );
|
|
nsCOMPtr<nsISupportsInterfacePointer> ptrPrimitive(do_QueryInterface(transferSupports));
|
|
#ifndef MOZ_CAIRO_GFX
|
|
nsCOMPtr<nsIImageMac> image;
|
|
if (ptrPrimitive) {
|
|
nsCOMPtr<nsISupports> primitiveData;
|
|
ptrPrimitive->GetData(getter_AddRefs(primitiveData));
|
|
image = do_QueryInterface(primitiveData);
|
|
}
|
|
if ( image ) {
|
|
PicHandle picture = nsnull;
|
|
image->ConvertToPICT ( &picture );
|
|
if ( picture ) {
|
|
errCode = PutOnClipboard ( 'PICT', *picture, ::GetHandleSize((Handle)picture) );
|
|
::KillPicture ( picture );
|
|
}
|
|
}
|
|
else
|
|
#endif
|
|
NS_WARNING ( "Image isn't an nsIImageMac in transferable" );
|
|
}
|
|
else if (strcmp(flavorStr.get(), kURLDataMime) == 0 ||
|
|
strcmp(flavorStr.get(), kURLDescriptionMime) == 0) {
|
|
nsCOMPtr<nsISupports> genericDataWrapper;
|
|
errCode = mTransferable->GetTransferData(
|
|
flavorStr,
|
|
getter_AddRefs(genericDataWrapper),
|
|
&dataSize);
|
|
if (NS_SUCCEEDED(errCode)) {
|
|
nsPrimitiveHelpers::CreateDataFromPrimitive(flavorStr,
|
|
genericDataWrapper,
|
|
&data,
|
|
dataSize);
|
|
|
|
// Transform the line break format from Unix-style '\n' to
|
|
// classic Mac-style '\r', as expected on the clipboard.
|
|
PRUnichar* castedData = NS_REINTERPRET_CAST(PRUnichar*, data);
|
|
PRUnichar* linebreakConvertedUnicode = castedData;
|
|
nsLinebreakConverter::ConvertUnicharLineBreaksInSitu(
|
|
&linebreakConvertedUnicode,
|
|
nsLinebreakConverter::eLinebreakUnix,
|
|
nsLinebreakConverter::eLinebreakMac,
|
|
dataSize / sizeof(PRUnichar),
|
|
nsnull);
|
|
|
|
// kURLDataMime ('url ') goes onto the clipboard in an 8-bit
|
|
// encoding using the %-escaped ASCII subset. The URL has already
|
|
// been %-escaped, so convert it from UTF-16 on the transferable to
|
|
// UTF-8 because it's easy. UTF-8 will also be used for
|
|
// kURLDescriptionMime ('urld'), URLs that carry a description, for
|
|
// congruity and to avoid using endian-dependent UTF-16 where the
|
|
// flavor is not mapped as a private 'MZ..' (see 340071), even
|
|
// though 'urld' is not used by others.
|
|
nsDependentString utf16(linebreakConvertedUnicode);
|
|
NS_ConvertUTF16toUTF8 utf8(utf16);
|
|
PutOnClipboard(macOSFlavor,
|
|
PromiseFlatCString(utf8).get(), utf8.Length());
|
|
|
|
// ConvertUnicharLineBreaksInSitu may have allocated a new buffer
|
|
// (although unlikely when converting from '\n' to '\r').
|
|
if (linebreakConvertedUnicode != castedData)
|
|
nsMemory::Free(linebreakConvertedUnicode);
|
|
}
|
|
}
|
|
else {
|
|
// we don't know what we have. let's just assume it's unicode but doesn't need to be
|
|
// translated to TEXT.
|
|
nsCOMPtr<nsISupports> genericDataWrapper;
|
|
errCode = mTransferable->GetTransferData ( flavorStr, getter_AddRefs(genericDataWrapper), &dataSize );
|
|
nsPrimitiveHelpers::CreateDataFromPrimitive ( flavorStr, genericDataWrapper, &data, dataSize );
|
|
errCode = PutOnClipboard ( macOSFlavor, data, dataSize );
|
|
}
|
|
|
|
nsMemory::Free ( data );
|
|
}
|
|
} // foreach flavor in transferable
|
|
|
|
// write out the mapping data in a special flavor on the clipboard. |mappingLen|
|
|
// includes the NULL terminator.
|
|
short mappingLen = 0;
|
|
const char* mapping = theMapper.ExportMapping(&mappingLen);
|
|
if ( mapping && mappingLen ) {
|
|
errCode = PutOnClipboard ( nsMimeMapperMac::MappingFlavor(), mapping, mappingLen );
|
|
nsCRT::free ( NS_CONST_CAST(char*, mapping) );
|
|
}
|
|
|
|
return errCode;
|
|
|
|
} // SetNativeClipboardData
|
|
|
|
|
|
//
|
|
// PutOnClipboard
|
|
//
|
|
// Actually does the work of placing the data on the native clipboard
|
|
// in the given flavor
|
|
//
|
|
nsresult
|
|
nsClipboard :: PutOnClipboard ( ResType inFlavor, const void* inData, PRInt32 inLen )
|
|
{
|
|
nsresult errCode = NS_OK;
|
|
|
|
void* data = (void*) inData;
|
|
if ((inFlavor & kPrivateFlavorMask) == kPrivateFlavorTag) {
|
|
// Byte-swap private flavors if running translated
|
|
nsCOMPtr<nsIMacUtils> macUtils =
|
|
do_GetService("@mozilla.org/xpcom/mac-utils;1");
|
|
PRBool isTranslated;
|
|
if (macUtils &&
|
|
NS_SUCCEEDED(macUtils->GetIsTranslated(&isTranslated)) &&
|
|
isTranslated) {
|
|
data = nsMemory::Alloc(inLen);
|
|
if (!data)
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
|
|
swab(inData, data, inLen);
|
|
}
|
|
}
|
|
|
|
ScrapRef scrap;
|
|
::GetCurrentScrap(&scrap);
|
|
::PutScrapFlavor( scrap, inFlavor, kScrapFlavorMaskNone, inLen, data );
|
|
|
|
if (data != inData)
|
|
nsMemory::Free(data);
|
|
|
|
return errCode;
|
|
|
|
} // PutOnClipboard
|
|
|
|
|
|
//
|
|
// GetNativeClipboardData
|
|
//
|
|
// Take data off the native clip and put it on the transferable.
|
|
//
|
|
NS_IMETHODIMP
|
|
nsClipboard :: GetNativeClipboardData ( nsITransferable * aTransferable, PRInt32 aWhichClipboard )
|
|
{
|
|
if ( aWhichClipboard != kGlobalClipboard )
|
|
return NS_ERROR_FAILURE;
|
|
|
|
nsresult errCode = NS_OK;
|
|
|
|
// make sure we have a good transferable
|
|
if ( !aTransferable )
|
|
return NS_ERROR_INVALID_ARG;
|
|
|
|
// get flavor list that includes all acceptable flavors (including ones obtained through
|
|
// conversion)
|
|
nsCOMPtr<nsISupportsArray> flavorList;
|
|
errCode = aTransferable->FlavorsTransferableCanImport ( getter_AddRefs(flavorList) );
|
|
if ( NS_FAILED(errCode) )
|
|
return NS_ERROR_FAILURE;
|
|
|
|
// create a mime mapper. It's ok for this to fail because the data may come from
|
|
// another app which obviously wouldn't put our mime mapping data on the clipboard.
|
|
char* mimeMapperData = nsnull;
|
|
errCode = GetDataOffClipboard ( nsMimeMapperMac::MappingFlavor(), (void**)&mimeMapperData, 0 );
|
|
nsMimeMapperMac theMapper ( mimeMapperData );
|
|
if (mimeMapperData)
|
|
nsCRT::free ( mimeMapperData );
|
|
|
|
// Now walk down the list of flavors. When we find one that is actually on the
|
|
// clipboard, copy out the data into the transferable in that format. SetTransferData()
|
|
// implicitly handles conversions.
|
|
PRBool dataFound = PR_FALSE;
|
|
PRUint32 cnt;
|
|
flavorList->Count(&cnt);
|
|
for ( PRUint32 i = 0; i < cnt; ++i ) {
|
|
nsCOMPtr<nsISupports> genericFlavor;
|
|
flavorList->GetElementAt ( i, getter_AddRefs(genericFlavor) );
|
|
nsCOMPtr<nsISupportsCString> currentFlavor ( do_QueryInterface(genericFlavor) );
|
|
if ( currentFlavor ) {
|
|
nsXPIDLCString flavorStr;
|
|
currentFlavor->ToString ( getter_Copies(flavorStr) );
|
|
|
|
// find MacOS flavor (don't add if not present)
|
|
ResType macOSFlavor = theMapper.MapMimeTypeToMacOSType(flavorStr, PR_FALSE);
|
|
|
|
void* clipboardData = nsnull;
|
|
PRInt32 dataSize = 0L;
|
|
nsresult loadResult = GetDataOffClipboard ( macOSFlavor, &clipboardData, &dataSize );
|
|
if ( NS_SUCCEEDED(loadResult) && clipboardData )
|
|
dataFound = PR_TRUE;
|
|
else {
|
|
// if we are looking for text/unicode and we fail to find it on the clipboard first,
|
|
// try again with text/plain. If that is present, convert it to unicode.
|
|
if ( strcmp(flavorStr, kUnicodeMime) == 0 ) {
|
|
|
|
// if 'styl' is available, we can get a script of the first run
|
|
// and use it for converting 'TEXT'
|
|
loadResult = GetDataOffClipboard ( 'styl', &clipboardData, &dataSize );
|
|
if (NS_SUCCEEDED(loadResult) &&
|
|
clipboardData &&
|
|
((PRUint32)dataSize >= (sizeof(ScrpSTElement) + 2))) {
|
|
StScrpRec *scrpRecP = (StScrpRec *) clipboardData;
|
|
ScrpSTElement *styl = scrpRecP->scrpStyleTab;
|
|
ScriptCode script = styl ? ::FontToScript(styl->scrpFont) : smCurrentScript;
|
|
|
|
// free 'styl' and get 'TEXT'
|
|
nsMemory::Free(clipboardData);
|
|
loadResult = GetDataOffClipboard ( 'TEXT', &clipboardData, &dataSize );
|
|
if ( NS_SUCCEEDED(loadResult) && clipboardData ) {
|
|
PRUnichar* convertedText = nsnull;
|
|
PRInt32 convertedTextLen = 0;
|
|
errCode = nsMacNativeUnicodeConverter::ConvertScripttoUnicode(
|
|
script,
|
|
(const char *) clipboardData,
|
|
dataSize,
|
|
&convertedText,
|
|
&convertedTextLen);
|
|
if (NS_SUCCEEDED(errCode) && convertedText) {
|
|
nsMemory::Free(clipboardData);
|
|
clipboardData = convertedText;
|
|
dataSize = convertedTextLen * sizeof(PRUnichar);
|
|
dataFound = PR_TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!dataFound) {
|
|
loadResult = GetDataOffClipboard ( 'TEXT', &clipboardData, &dataSize );
|
|
if ( NS_SUCCEEDED(loadResult) && clipboardData ) {
|
|
const char* castedText = NS_REINTERPRET_CAST(char*, clipboardData);
|
|
PRUnichar* convertedText = nsnull;
|
|
PRInt32 convertedTextLen = 0;
|
|
nsPrimitiveHelpers::ConvertPlatformPlainTextToUnicode ( castedText, dataSize,
|
|
&convertedText, &convertedTextLen );
|
|
if ( convertedText ) {
|
|
// out with the old, in with the new
|
|
nsMemory::Free(clipboardData);
|
|
clipboardData = convertedText;
|
|
dataSize = convertedTextLen * 2;
|
|
dataFound = PR_TRUE;
|
|
}
|
|
} // if plain text data on clipboard
|
|
}
|
|
} // if looking for text/unicode
|
|
} // else we try one last ditch effort to find our data
|
|
|
|
if ( dataFound ) {
|
|
if ( strcmp(flavorStr, kPNGImageMime) == 0 || strcmp(flavorStr, kJPEGImageMime) == 0 ||
|
|
strcmp(flavorStr, kGIFImageMime) == 0 ) {
|
|
// someone asked for an image, so we have to convert from PICT to the desired
|
|
// image format
|
|
|
|
#ifdef DEBUG
|
|
printf ( "----------- IMAGE REQUESTED ----------" );
|
|
#endif
|
|
|
|
} // if image requested
|
|
else {
|
|
if (strcmp(flavorStr.get(), kURLDataMime) == 0 ||
|
|
strcmp(flavorStr.get(), kURLDescriptionMime) == 0) {
|
|
// kURLDataMime ('url ') exists on the clipboard in a %-encoded
|
|
// subset of ASCII. It belongs on the transferable in UTF-16.
|
|
// The %-encoding may remain intact, so this is handled by
|
|
// converting UTF-8 to UTF-16. kURLDescriptionMime ('urld'),
|
|
// URLs carrying a description, are also treated to the same
|
|
// conversion because it's used when the data is copied to the
|
|
// clipboard.
|
|
nsDependentCString utf8(NS_REINTERPRET_CAST(char*, clipboardData));
|
|
NS_ConvertUTF8toUTF16 utf16(utf8);
|
|
|
|
// Replace clipboardData with the new wide-char version.
|
|
nsMemory::Free(clipboardData);
|
|
clipboardData = ToNewUnicode(utf16);
|
|
dataSize = utf16.Length() * 2;
|
|
}
|
|
|
|
// Assume that we have some form of textual data. The DOM only wants LF, so convert
|
|
// from MacOS line endings to DOM line endings.
|
|
nsLinebreakHelpers::ConvertPlatformToDOMLinebreaks ( flavorStr, &clipboardData, &dataSize );
|
|
|
|
unsigned char *clipboardDataPtr = (unsigned char *) clipboardData;
|
|
// skip BOM (Byte Order Mark to distinguish little or big endian) in 'utxt'
|
|
// 10.2 puts BOM for 'utxt', we need to remove it here
|
|
// for little endian case, we also need to convert the data to big endian
|
|
// but we do not do that currently (need this in case 'utxt' is really in little endian)
|
|
if ( (macOSFlavor == 'utxt') &&
|
|
(dataSize > 2) &&
|
|
((clipboardDataPtr[0] == 0xFE && clipboardDataPtr[1] == 0xFF) ||
|
|
(clipboardDataPtr[0] == 0xFF && clipboardDataPtr[1] == 0xFE)) ) {
|
|
dataSize -= sizeof(PRUnichar);
|
|
clipboardDataPtr += sizeof(PRUnichar);
|
|
}
|
|
|
|
// put it into the transferable
|
|
nsCOMPtr<nsISupports> genericDataWrapper;
|
|
nsPrimitiveHelpers::CreatePrimitiveForData ( flavorStr, clipboardDataPtr, dataSize, getter_AddRefs(genericDataWrapper) );
|
|
errCode = aTransferable->SetTransferData ( flavorStr, genericDataWrapper, dataSize );
|
|
}
|
|
|
|
nsMemory::Free ( clipboardData );
|
|
|
|
// we found one, get out of this loop!
|
|
break;
|
|
} // if flavor found on clipboard
|
|
}
|
|
} // foreach flavor
|
|
|
|
return errCode;
|
|
}
|
|
|
|
|
|
//
|
|
// GetDataOffClipboard
|
|
//
|
|
// Actually does the work of retrieving the data from the native clipboard
|
|
// with the given MacOS flavor
|
|
//
|
|
nsresult
|
|
nsClipboard :: GetDataOffClipboard ( ResType inMacFlavor, void** outData, PRInt32* outDataSize )
|
|
{
|
|
if ( !outData || !inMacFlavor )
|
|
return NS_ERROR_FAILURE;
|
|
|
|
// set up default results.
|
|
*outData = nsnull;
|
|
if ( outDataSize )
|
|
*outDataSize = 0;
|
|
|
|
|
|
ScrapRef scrap;
|
|
long dataSize;
|
|
OSStatus err;
|
|
|
|
err = ::GetCurrentScrap(&scrap);
|
|
if (err != noErr) return NS_ERROR_FAILURE;
|
|
err = ::GetScrapFlavorSize(scrap, inMacFlavor, &dataSize);
|
|
if (err != noErr) return NS_ERROR_FAILURE;
|
|
if (dataSize > 0) {
|
|
char* dataBuff = (char*) nsMemory::Alloc(dataSize);
|
|
if ( !dataBuff )
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
|
|
// ::GetScrapFlavorData can be very expensive when a conversion
|
|
// is required (say the OS does the conversion from TEXT to utxt). Be
|
|
// sure to only call this when pasting. We no longer use it in
|
|
// CheckIfFlavorPresent() for this very reason.
|
|
err = ::GetScrapFlavorData(scrap, inMacFlavor, &dataSize, dataBuff);
|
|
NS_ASSERTION(err == noErr, "nsClipboard:: Error getting data off clipboard");
|
|
if ( err ) {
|
|
nsMemory::Free(dataBuff);
|
|
return NS_ERROR_FAILURE;
|
|
}
|
|
|
|
if ((inMacFlavor & kPrivateFlavorMask) == kPrivateFlavorTag) {
|
|
// Byte-swap private flavors if running translated
|
|
nsCOMPtr<nsIMacUtils> macUtils =
|
|
do_GetService("@mozilla.org/xpcom/mac-utils;1");
|
|
PRBool isTranslated;
|
|
if (macUtils &&
|
|
NS_SUCCEEDED(macUtils->GetIsTranslated(&isTranslated)) &&
|
|
isTranslated) {
|
|
char* swappedData = (char*) nsMemory::Alloc(dataSize);
|
|
if (!swappedData) {
|
|
nsMemory::Free(dataBuff);
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
}
|
|
|
|
swab(dataBuff, swappedData, dataSize);
|
|
nsMemory::Free(dataBuff);
|
|
dataBuff = swappedData;
|
|
}
|
|
}
|
|
|
|
// put it into the transferable
|
|
if ( outDataSize )
|
|
*outDataSize = dataSize;
|
|
*outData = dataBuff;
|
|
}
|
|
return NS_OK;
|
|
|
|
} // GetDataOffClipboard
|
|
|
|
|
|
//
|
|
// HasDataMatchingFlavors
|
|
//
|
|
// Check the clipboard to see if we have any data that matches the given flavors. This
|
|
// does NOT actually fetch the data. The items in the flavor list are nsISupportsCString's.
|
|
//
|
|
// Handle the case where we ask for unicode and it's not there, but plain text is. We
|
|
// say "yes" in that case, knowing that we will have to perform a conversion when we actually
|
|
// pull the data off the clipboard.
|
|
//
|
|
NS_IMETHODIMP
|
|
nsClipboard :: HasDataMatchingFlavors ( nsISupportsArray* aFlavorList, PRInt32 aWhichClipboard, PRBool * outResult )
|
|
{
|
|
nsresult rv = NS_OK;
|
|
*outResult = PR_FALSE; // assume there is nothing there we want.
|
|
if ( aWhichClipboard != kGlobalClipboard )
|
|
return NS_OK;
|
|
|
|
// create a mime mapper. It's ok for this to fail because the data may come from
|
|
// another app which obviously wouldn't put our mime mapping data on the clipboard.
|
|
char* mimeMapperData = nsnull;
|
|
rv = GetDataOffClipboard ( nsMimeMapperMac::MappingFlavor(), (void**)&mimeMapperData, 0 );
|
|
nsMimeMapperMac theMapper ( mimeMapperData );
|
|
nsMemory::Free ( mimeMapperData );
|
|
|
|
PRUint32 length;
|
|
aFlavorList->Count(&length);
|
|
for ( PRUint32 i = 0; i < length; ++i ) {
|
|
nsCOMPtr<nsISupports> genericFlavor;
|
|
aFlavorList->GetElementAt ( i, getter_AddRefs(genericFlavor) );
|
|
nsCOMPtr<nsISupportsCString> flavorWrapper ( do_QueryInterface(genericFlavor) );
|
|
if ( flavorWrapper ) {
|
|
nsXPIDLCString flavor;
|
|
flavorWrapper->ToString ( getter_Copies(flavor) );
|
|
|
|
#ifdef NS_DEBUG
|
|
if ( strcmp(flavor, kTextMime) == 0 )
|
|
NS_WARNING ( "DO NOT USE THE text/plain DATA FLAVOR ANY MORE. USE text/unicode INSTEAD" );
|
|
#endif
|
|
|
|
// now that we have the flavor (whew!), run it through the mime mapper. If
|
|
// the mapper returns a null flavor, then it ain't there.
|
|
ResType macFlavor = theMapper.MapMimeTypeToMacOSType ( flavor, PR_FALSE );
|
|
if ( macFlavor ) {
|
|
if ( CheckIfFlavorPresent(macFlavor) ) {
|
|
*outResult = PR_TRUE; // we found one!
|
|
break;
|
|
}
|
|
else {
|
|
// if the client asked for unicode and it wasn't present, check if we have TEXT.
|
|
// We'll handle the actual data substitution in GetNativeClipboardData().
|
|
if ( strcmp(flavor, kUnicodeMime) == 0 ) {
|
|
if ( CheckIfFlavorPresent('TEXT') ) {
|
|
*outResult = PR_TRUE;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} // foreach flavor
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
|
|
//
|
|
// CheckIfFlavorPresent
|
|
//
|
|
// A little utility routine for derminining if a given flavor is really there
|
|
//
|
|
PRBool
|
|
nsClipboard :: CheckIfFlavorPresent ( ResType inMacFlavor )
|
|
{
|
|
PRBool retval = PR_FALSE;
|
|
|
|
ScrapRef scrap = nsnull;
|
|
OSStatus err = ::GetCurrentScrap(&scrap);
|
|
if ( scrap ) {
|
|
|
|
// the OS clipboard may contain promises and require conversions. Instead
|
|
// of calling in those promises, we can use ::GetScrapFlavorInfoList() to
|
|
// see the list of what could be there if we asked for it. This is really
|
|
// fast. Iterate over the list, and if we find it, we're good to go.
|
|
UInt32 flavorCount = 0;
|
|
::GetScrapFlavorCount ( scrap, &flavorCount );
|
|
nsAutoArrayPtr<ScrapFlavorInfo> flavorList(new ScrapFlavorInfo[flavorCount]);
|
|
if ( flavorList ) {
|
|
err = ::GetScrapFlavorInfoList ( scrap, &flavorCount, flavorList );
|
|
if ( !err && flavorList ) {
|
|
for ( unsigned int i = 0; i < flavorCount; ++i ) {
|
|
if ( flavorList[i].flavorType == inMacFlavor )
|
|
retval = PR_TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
return retval;
|
|
} // CheckIfFlavorPresent
|