gecko-dev/widget/os2/nsClipboard.cpp
2012-10-04 02:14:06 -04:00

415 lines
13 KiB
C++

/* -*- 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/. */
#include "nsXPCOM.h"
#include "nsISupportsPrimitives.h"
#include "nsCOMPtr.h"
#include "nsPrimitiveHelpers.h"
#include "nsXPIDLString.h"
#include "nsOS2Uni.h"
#include "nsClipboard.h"
#define INCL_DOSERRORS
#define INCL_WIN
#include <os2.h>
inline uint32_t RegisterClipboardFormat(PCSZ pcszFormat)
{
ATOM atom = WinFindAtom(WinQuerySystemAtomTable(), pcszFormat);
if (!atom) {
atom = WinAddAtom(WinQuerySystemAtomTable(), pcszFormat);
}
return atom;
}
nsClipboard::nsClipboard() : nsBaseClipboard()
{
RegisterClipboardFormat(kTextMime);
RegisterClipboardFormat(kUnicodeMime);
RegisterClipboardFormat(kHTMLMime);
RegisterClipboardFormat(kAOLMailMime);
RegisterClipboardFormat(kPNGImageMime);
RegisterClipboardFormat(kJPEGImageMime);
RegisterClipboardFormat(kJPGImageMime);
RegisterClipboardFormat(kGIFImageMime);
RegisterClipboardFormat(kFileMime);
RegisterClipboardFormat(kURLMime);
RegisterClipboardFormat(kNativeImageMime);
RegisterClipboardFormat(kNativeHTMLMime);
}
nsClipboard::~nsClipboard()
{}
nsresult nsClipboard::SetNativeClipboardData(int32_t aWhichClipboard)
{
if (aWhichClipboard != kGlobalClipboard)
return NS_ERROR_FAILURE;
return DoClipboardAction(Write);
}
nsresult nsClipboard::GetNativeClipboardData(nsITransferable *aTransferable, int32_t aWhichClipboard)
{
// make sure we have a good transferable
if (!aTransferable || aWhichClipboard != kGlobalClipboard)
return NS_ERROR_FAILURE;
nsITransferable *tmp = mTransferable;
mTransferable = aTransferable;
nsresult rc = DoClipboardAction(Read);
mTransferable = tmp;
return rc;
}
// Get some data from the clipboard
bool nsClipboard::GetClipboardData(const char *aFlavor)
{
uint32_t ulFormatID = GetFormatID(aFlavor);
bool found = GetClipboardDataByID( ulFormatID, aFlavor );
if (!found)
{
if (!strcmp( aFlavor, kUnicodeMime ))
{
found = GetClipboardDataByID( CF_TEXT, aFlavor );
}
else if (strstr( aFlavor, "image/" ))
{
found = GetClipboardDataByID( CF_BITMAP, aFlavor );
}
}
return found;
}
bool nsClipboard::GetClipboardDataByID(uint32_t aFormatID, const char *aFlavor)
{
PVOID pDataMem;
uint32_t NumOfBytes;
bool TempBufAllocated = false;
PVOID pClipboardData = reinterpret_cast<PVOID>(WinQueryClipbrdData(0, aFormatID));
if (!pClipboardData)
return false;
if (strstr( aFlavor, "text/" )) // All text/.. flavors are null-terminated
{
pDataMem = pClipboardData;
if (aFormatID == CF_TEXT) // CF_TEXT is one byte character set
{
uint32_t NumOfChars = strlen( static_cast<char*>(pDataMem) );
NumOfBytes = NumOfChars;
if (!strcmp( aFlavor, kUnicodeMime )) // Asked for unicode, but only plain text available. Convert it!
{
nsAutoChar16Buffer buffer;
int32_t bufLength;
MultiByteToWideChar(0, static_cast<char*>(pDataMem), NumOfChars,
buffer, bufLength);
pDataMem = ToNewUnicode(nsDependentString(buffer.Elements()));
TempBufAllocated = true;
NumOfBytes = bufLength * sizeof(UniChar);
}
}
else // All other text/.. flavors are in unicode
{
uint32_t NumOfChars = UniStrlen( static_cast<UniChar*>(pDataMem) );
NumOfBytes = NumOfChars * sizeof(UniChar);
PVOID pTempBuf = nsMemory::Alloc(NumOfBytes);
memcpy(pTempBuf, pDataMem, NumOfBytes);
pDataMem = pTempBuf;
TempBufAllocated = true;
}
// DOM wants LF only, so convert from CRLF
nsLinebreakHelpers::ConvertPlatformToDOMLinebreaks( aFlavor, &pDataMem, // pDataMem could be reallocated !!
reinterpret_cast<int32_t*>(&NumOfBytes) ); // yuck
}
else // Assume rest of flavors are binary data
{
if (aFormatID == CF_BITMAP)
{
if (!strcmp( aFlavor, kJPEGImageMime ) || !strcmp( aFlavor, kJPGImageMime ))
{
// OS2TODO Convert bitmap to jpg
#ifdef DEBUG
printf( "nsClipboard:: No JPG found on clipboard; need to convert BMP\n");
#endif
}
else if (!strcmp( aFlavor, kGIFImageMime ))
{
// OS2TODO Convert bitmap to gif
#ifdef DEBUG
printf( "nsClipboard:: No GIF found on clipboard; need to convert BMP\n");
#endif
}
else if (!strcmp( aFlavor, kPNGImageMime ))
{
// OS2TODO Convert bitmap to png
#ifdef DEBUG
printf( "nsClipboard:: No PNG found on clipboard; need to convert BMP\n");
#endif
}
}
else
{
pDataMem = static_cast<PBYTE>(pClipboardData) + sizeof(uint32_t);
NumOfBytes = *(static_cast<uint32_t*>(pClipboardData));
}
}
nsCOMPtr<nsISupports> genericDataWrapper;
nsPrimitiveHelpers::CreatePrimitiveForData( aFlavor, pDataMem, NumOfBytes, getter_AddRefs(genericDataWrapper) );
#ifdef DEBUG
nsresult errCode =
#endif
mTransferable->SetTransferData( aFlavor, genericDataWrapper, NumOfBytes );
#ifdef DEBUG
if (errCode != NS_OK)
printf( "nsClipboard:: Error setting data into transferable\n" );
#endif
if (TempBufAllocated)
nsMemory::Free(pDataMem);
return true;
}
// Set some data onto the clipboard
void nsClipboard::SetClipboardData(const char *aFlavor)
{
void *pMozData = nullptr;
uint32_t NumOfBytes = 0;
// Get the data from the transferable
nsCOMPtr<nsISupports> genericDataWrapper;
#ifdef DEBUG
nsresult errCode =
#endif
mTransferable->GetTransferData( aFlavor, getter_AddRefs(genericDataWrapper), &NumOfBytes );
#ifdef DEBUG
if (NS_FAILED(errCode)) printf( "nsClipboard:: Error getting data from transferable\n" );
#endif
if (NumOfBytes == 0) return;
nsPrimitiveHelpers::CreateDataFromPrimitive( aFlavor, genericDataWrapper, &pMozData, NumOfBytes );
/* If creating the data failed, just return */
if (!pMozData) {
return;
}
uint32_t ulFormatID = GetFormatID(aFlavor);
if (strstr( aFlavor, "text/" )) // All text/.. flavors are null-terminated
{
if (ulFormatID == CF_TEXT) // CF_TEXT is one byte character set
{
char* pByteMem = nullptr;
if (DosAllocSharedMem( reinterpret_cast<PPVOID>(&pByteMem), nullptr, NumOfBytes + sizeof(char),
PAG_WRITE | PAG_COMMIT | OBJ_GIVEABLE ) == NO_ERROR)
{
memcpy( pByteMem, pMozData, NumOfBytes ); // Copy text string
pByteMem[NumOfBytes] = '\0'; // Append terminator
// With Warp4 copying more than 64K to the clipboard works well, but
// legacy apps cannot always handle it. So output an alarm to alert the
// user that there might be a problem.
if (strlen(pByteMem) > 0xFFFF) {
WinAlarm(HWND_DESKTOP, WA_ERROR);
}
WinSetClipbrdData(0, reinterpret_cast<ULONG>(pByteMem), ulFormatID, CFI_POINTER);
}
}
else // All other text/.. flavors are in unicode
{
UniChar* pUnicodeMem = nullptr;
uint32_t NumOfChars = NumOfBytes / sizeof(UniChar);
if (DosAllocSharedMem( reinterpret_cast<PPVOID>(&pUnicodeMem), nullptr, NumOfBytes + sizeof(UniChar),
PAG_WRITE | PAG_COMMIT | OBJ_GIVEABLE ) == NO_ERROR)
{
memcpy( pUnicodeMem, pMozData, NumOfBytes ); // Copy text string
pUnicodeMem[NumOfChars] = L'\0'; // Append terminator
WinSetClipbrdData( 0, reinterpret_cast<ULONG>(pUnicodeMem), ulFormatID, CFI_POINTER );
}
// If the flavor is unicode, we also put it on the clipboard as CF_TEXT
// after conversion to locale charset.
if (!strcmp( aFlavor, kUnicodeMime ))
{
char* pByteMem = nullptr;
if (DosAllocSharedMem(reinterpret_cast<PPVOID>(&pByteMem), nullptr,
NumOfBytes + 1,
PAG_WRITE | PAG_COMMIT | OBJ_GIVEABLE ) == NO_ERROR)
{
PRUnichar* uchtemp = (PRUnichar*)pMozData;
for (uint32_t i=0;i<NumOfChars;i++) {
switch (uchtemp[i]) {
case 0x2018:
case 0x2019:
uchtemp[i] = 0x0027;
break;
case 0x201C:
case 0x201D:
uchtemp[i] = 0x0022;
break;
case 0x2014:
uchtemp[i] = 0x002D;
break;
}
}
nsAutoCharBuffer buffer;
int32_t bufLength;
WideCharToMultiByte(0, static_cast<PRUnichar*>(pMozData),
NumOfBytes, buffer, bufLength);
memcpy(pByteMem, buffer.Elements(), NumOfBytes);
// With Warp4 copying more than 64K to the clipboard works well, but
// legacy apps cannot always handle it. So output an alarm to alert the
// user that there might be a problem.
if (strlen(pByteMem) > 0xFFFF) {
WinAlarm(HWND_DESKTOP, WA_ERROR);
}
WinSetClipbrdData(0, reinterpret_cast<ULONG>(pByteMem), CF_TEXT, CFI_POINTER);
}
}
}
}
else // Assume rest of flavors are binary data
{
PBYTE pBinaryMem = nullptr;
if (DosAllocSharedMem( reinterpret_cast<PPVOID>(&pBinaryMem), nullptr, NumOfBytes + sizeof(uint32_t),
PAG_WRITE | PAG_COMMIT | OBJ_GIVEABLE ) == NO_ERROR)
{
*(reinterpret_cast<uint32_t*>(pBinaryMem)) = NumOfBytes; // First DWORD contains data length
memcpy( pBinaryMem + sizeof(uint32_t), pMozData, NumOfBytes ); // Copy binary data
WinSetClipbrdData( 0, reinterpret_cast<ULONG>(pBinaryMem), ulFormatID, CFI_POINTER );
}
// If the flavor is image, we also put it on clipboard as CF_BITMAP
// after conversion to OS2 bitmap
if (strstr (aFlavor, "image/"))
{
// XXX OS2TODO Convert jpg, gif, png to bitmap
#ifdef DEBUG
printf( "nsClipboard:: Putting image on clipboard; should also convert to BMP\n" );
#endif
}
}
nsMemory::Free(pMozData);
}
// Go through the flavors in the transferable and either get or set them
nsresult nsClipboard::DoClipboardAction(ClipboardAction aAction)
{
nsresult rc = NS_ERROR_FAILURE;
if (WinOpenClipbrd(0/*hab*/)) {
if (aAction == Write)
WinEmptyClipbrd(0/*hab*/);
// Get the list of formats the transferable can handle
nsCOMPtr<nsISupportsArray> pFormats;
if(aAction == Read)
rc = mTransferable->FlavorsTransferableCanImport(getter_AddRefs(pFormats));
else
rc = mTransferable->FlavorsTransferableCanExport(getter_AddRefs(pFormats));
if (NS_FAILED(rc))
return NS_ERROR_FAILURE;
uint32_t cFormats = 0;
pFormats->Count(&cFormats);
for (uint32_t i = 0; i < cFormats; i++) {
nsCOMPtr<nsISupports> genericFlavor;
pFormats->GetElementAt(i, getter_AddRefs(genericFlavor));
nsCOMPtr<nsISupportsCString> currentFlavor(do_QueryInterface(genericFlavor));
if (currentFlavor) {
nsXPIDLCString flavorStr;
currentFlavor->ToString(getter_Copies(flavorStr));
if (aAction == Read) {
if (GetClipboardData(flavorStr))
break;
}
else
SetClipboardData(flavorStr);
}
}
WinCloseClipbrd(0/*hab*/);
rc = NS_OK;
}
return rc;
}
// get the format ID for a given mimetype
uint32_t nsClipboard::GetFormatID(const char *aMimeStr)
{
if (strcmp(aMimeStr, kTextMime) == 0)
return CF_TEXT;
return RegisterClipboardFormat(aMimeStr);
}
NS_IMETHODIMP nsClipboard::HasDataMatchingFlavors(const char** aFlavorList,
uint32_t aLength,
int32_t aWhichClipboard,
bool *_retval)
{
*_retval = false;
if (aWhichClipboard != kGlobalClipboard || !aFlavorList)
return NS_OK;
for (uint32_t i = 0; i < aLength; ++i) {
ULONG fmtInfo = 0;
uint32_t format = GetFormatID(aFlavorList[i]);
if (WinQueryClipbrdFmtInfo(0/*hab*/, format, &fmtInfo)) {
*_retval = true;
break;
}
// if the client asked for unicode and it wasn't present, check if we have CF_TEXT.
if (!strcmp(aFlavorList[i], kUnicodeMime)) {
if (WinQueryClipbrdFmtInfo(0/*hab*/, CF_TEXT, &fmtInfo)) {
*_retval = true;
break;
}
}
// OS2TODO - Support for Images
// if the client asked for image/.. and it wasn't present, check if we have CF_BITMAP.
if (strstr(aFlavorList[i], "image/")) {
if (WinQueryClipbrdFmtInfo (0, CF_BITMAP, &fmtInfo)) {
#ifdef DEBUG
printf("nsClipboard:: Image present on clipboard; need to add BMP conversion!\n");
#endif
// *_retval = true;
// break;
}
}
}
return NS_OK;
}