Bug 860857, support custom datatransfer types using a special type, r=smaug,jmathies,mstange

This commit is contained in:
Neil Deakin 2016-04-21 14:11:14 -04:00
Родитель d614e66d46
Коммит a030ec3ce6
15 изменённых файлов: 453 добавлений и 113 удалений

Просмотреть файл

@ -18,6 +18,10 @@
#include "nsIClipboard.h"
#include "nsContentUtils.h"
#include "nsIContent.h"
#include "nsIBinaryInputStream.h"
#include "nsIBinaryOutputStream.h"
#include "nsIStorageStream.h"
#include "nsStringStream.h"
#include "nsCRT.h"
#include "nsIScriptObjectPrincipal.h"
#include "nsIScriptContext.h"
@ -80,6 +84,12 @@ const char DataTransfer::sEffects[8][9] = {
"none", "copy", "move", "copyMove", "link", "copyLink", "linkMove", "all"
};
// Used for custom clipboard types.
enum CustomClipboardTypeId {
eCustomClipboardTypeId_None,
eCustomClipboardTypeId_String
};
DataTransfer::DataTransfer(nsISupports* aParent, EventMessage aEventMessage,
bool aIsExternal, int32_t aClipboardType)
: mParent(aParent)
@ -710,6 +720,11 @@ DataTransfer::SetDataAtInternal(const nsAString& aFormat, nsIVariant* aData,
return NS_ERROR_DOM_INDEX_SIZE_ERR;
}
// Don't allow the custom type to be assigned.
if (aFormat.EqualsLiteral(kCustomTypesMime)) {
return NS_ERROR_TYPE_ERR;
}
// Don't allow non-chrome to add non-string or file data. We'll block file
// promises as well which are used internally for drags to the desktop.
if (!nsContentUtils::IsSystemPrincipal(aSubjectPrincipal)) {
@ -984,44 +999,166 @@ DataTransfer::GetTransferable(uint32_t aIndex, nsILoadContext* aLoadContext)
}
transferable->Init(aLoadContext);
nsCOMPtr<nsIStorageStream> storageStream;
nsCOMPtr<nsIBinaryOutputStream> stream;
bool added = false;
for (uint32_t f = 0; f < count; f++) {
const TransferItem& formatitem = item[f];
if (!formatitem.mData) { // skip empty items
continue;
bool handlingCustomFormats = true;
uint32_t totalCustomLength = 0;
const char* knownFormats[] = { kTextMime, kHTMLMime, kNativeHTMLMime, kRTFMime,
kURLMime, kURLDataMime, kURLDescriptionMime, kURLPrivateMime,
kPNGImageMime, kJPEGImageMime, kGIFImageMime, kNativeImageMime,
kFileMime, kFilePromiseMime, kFilePromiseDirectoryMime,
kMozTextInternal, kHTMLContext, kHTMLInfo };
/*
* Two passes are made here to iterate over all of the types. First, look for
* any types that are not in the list of known types. For this pass, handlingCustomFormats
* will be true. Data that corresponds to unknown types will be pulled out and
* inserted into a single type (kCustomTypesMime) by writing the data into a stream.
*
* The second pass will iterate over the formats looking for known types. These are
* added as is. The unknown types are all then inserted as a single type (kCustomTypesMime)
* in the same position of the first custom type. This model is used to maintain the
* format order as best as possible.
*
* The format of the kCustomTypesMime type is one or more of the following stored sequentially:
* <32-bit> type (only none or string is supported)
* <32-bit> length of format
* <wide string> format
* <32-bit> length of data
* <wide string> data
* A type of eCustomClipboardTypeId_None ends the list, without any following data.
*/
do {
for (uint32_t f = 0; f < count; f++) {
const TransferItem& formatitem = item[f];
if (!formatitem.mData) { // skip empty items
continue;
}
// If the data is of one of the well-known formats, use it directly.
bool isCustomFormat = true;
for (uint32_t f = 0; f < ArrayLength(knownFormats); f++) {
if (formatitem.mFormat.EqualsASCII(knownFormats[f])) {
isCustomFormat = false;
break;
}
}
uint32_t lengthInBytes;
nsCOMPtr<nsISupports> convertedData;
if (handlingCustomFormats) {
if (!ConvertFromVariant(formatitem.mData, getter_AddRefs(convertedData), &lengthInBytes)) {
continue;
}
// When handling custom types, add the data to the stream if this is a
// custom type.
if (isCustomFormat) {
// If it isn't a string, just ignore it. The dataTransfer is cached in the
// drag sesion during drag-and-drop, so non-strings will be available when
// dragging locally.
nsCOMPtr<nsISupportsString> str(do_QueryInterface(convertedData));
if (str) {
nsAutoString data;
str->GetData(data);
if (!stream) {
// Create a storage stream to write to.
NS_NewStorageStream(1024, UINT32_MAX, getter_AddRefs(storageStream));
nsCOMPtr<nsIOutputStream> outputStream;
storageStream->GetOutputStream(0, getter_AddRefs(outputStream));
stream = do_CreateInstance("@mozilla.org/binaryoutputstream;1");
stream->SetOutputStream(outputStream);
}
int32_t formatLength = formatitem.mFormat.Length() * sizeof(nsString::char_type);
stream->Write32(eCustomClipboardTypeId_String);
stream->Write32(formatLength);
stream->WriteBytes((const char *)formatitem.mFormat.get(), formatLength);
stream->Write32(lengthInBytes);
stream->WriteBytes((const char *)data.get(), lengthInBytes);
// The total size of the stream is the format length, the data length,
// two integers to hold the lengths and one integer for the string flag.
totalCustomLength += formatLength + lengthInBytes + (sizeof(uint32_t) * 3);
}
}
} else if (isCustomFormat && stream) {
// This is the second pass of the loop (handlingCustomFormats is false).
// When encountering the first custom format, append all of the stream
// at this position.
// Write out a terminator.
totalCustomLength += sizeof(uint32_t);
stream->Write32(eCustomClipboardTypeId_None);
nsCOMPtr<nsIInputStream> inputStream;
storageStream->NewInputStream(0, getter_AddRefs(inputStream));
RefPtr<nsStringBuffer> stringBuffer = nsStringBuffer::Alloc(totalCustomLength + 1);
// Read the data from the string and add a null-terminator as ToString needs it.
uint32_t amountRead;
inputStream->Read(static_cast<char*>(stringBuffer->Data()), totalCustomLength, &amountRead);
static_cast<char*>(stringBuffer->Data())[amountRead] = 0;
nsCString str;
stringBuffer->ToString(totalCustomLength, str);
nsCOMPtr<nsISupportsCString> strSupports(do_CreateInstance(NS_SUPPORTS_CSTRING_CONTRACTID));
strSupports->SetData(str);
nsresult rv = transferable->SetTransferData(kCustomTypesMime, strSupports, totalCustomLength);
if (NS_FAILED(rv)) {
return nullptr;
}
added = true;
// Clear the stream so it doesn't get used again.
stream = nullptr;
} else {
// This is the second pass of the loop and a known type is encountered.
// Add it as is.
if (!ConvertFromVariant(formatitem.mData, getter_AddRefs(convertedData), &lengthInBytes)) {
continue;
}
// The underlying drag code uses text/unicode, so use that instead of text/plain
const char* format;
NS_ConvertUTF16toUTF8 utf8format(formatitem.mFormat);
if (utf8format.EqualsLiteral(kTextMime)) {
format = kUnicodeMime;
} else {
format = utf8format.get();
}
// If a converter is set for a format, set the converter for the
// transferable and don't add the item
nsCOMPtr<nsIFormatConverter> converter = do_QueryInterface(convertedData);
if (converter) {
transferable->AddDataFlavor(format);
transferable->SetConverter(converter);
continue;
}
nsresult rv = transferable->SetTransferData(format, convertedData, lengthInBytes);
if (NS_FAILED(rv)) {
return nullptr;
}
added = true;
}
}
uint32_t length;
nsCOMPtr<nsISupports> convertedData;
if (!ConvertFromVariant(formatitem.mData, getter_AddRefs(convertedData), &length)) {
continue;
}
// the underlying drag code uses text/unicode, so use that instead of text/plain
const char* format;
NS_ConvertUTF16toUTF8 utf8format(formatitem.mFormat);
if (utf8format.EqualsLiteral("text/plain")) {
format = kUnicodeMime;
} else {
format = utf8format.get();
}
// if a converter is set for a format, set the converter for the
// transferable and don't add the item
nsCOMPtr<nsIFormatConverter> converter = do_QueryInterface(convertedData);
if (converter) {
transferable->AddDataFlavor(format);
transferable->SetConverter(converter);
continue;
}
nsresult rv = transferable->SetTransferData(format, convertedData, length);
if (NS_FAILED(rv)) {
return nullptr;
}
added = true;
}
handlingCustomFormats = !handlingCustomFormats;
} while (!handlingCustomFormats);
// only return the transferable if data was successfully added to it
if (added) {
@ -1152,6 +1289,19 @@ DataTransfer::SetDataWithPrincipal(const nsAString& aFormat,
return NS_OK;
}
void
DataTransfer::SetDataWithPrincipalFromOtherProcess(const nsAString& aFormat,
nsIVariant* aData,
uint32_t aIndex,
nsIPrincipal* aPrincipal)
{
if (aFormat.EqualsLiteral(kCustomTypesMime)) {
FillInExternalCustomTypes(aData, aIndex, aPrincipal);
} else {
SetDataWithPrincipal(aFormat, aData, aIndex, aPrincipal);
}
}
void
DataTransfer::GetRealFormat(const nsAString& aInFormat, nsAString& aOutFormat)
{
@ -1200,11 +1350,19 @@ DataTransfer::CacheExternalDragFormats()
// there isn't a way to get a list of the formats that might be available on
// all platforms, so just check for the types that can actually be imported
// XXXndeakin there are some other formats but those are platform specific.
const char* formats[] = { kFileMime, kHTMLMime, kRTFMime, kURLMime, kURLDataMime, kUnicodeMime };
const char* formats[] = { kFileMime, kHTMLMime, kRTFMime,
kURLMime, kURLDataMime, kUnicodeMime };
uint32_t count;
dragSession->GetNumDropItems(&count);
for (uint32_t c = 0; c < count; c++) {
// First, check for the special format that holds custom types.
bool supported;
dragSession->IsDataFlavorSupported(kCustomTypesMime, &supported);
if (supported) {
FillInExternalCustomTypes(c, sysPrincipal);
}
for (uint32_t f = 0; f < ArrayLength(formats); f++) {
// IsDataFlavorSupported doesn't take an index as an argument and just
// checks if any of the items support a particular flavor, even though
@ -1241,8 +1399,10 @@ DataTransfer::CacheExternalClipboardFormats()
ssm->GetSystemPrincipal(getter_AddRefs(sysPrincipal));
// there isn't a way to get a list of the formats that might be available on
// all platforms, so just check for the types that can actually be imported
const char* formats[] = { kFileMime, kHTMLMime, kRTFMime, kURLMime, kURLDataMime, kUnicodeMime };
// all platforms, so just check for the types that can actually be imported.
// Note that the loop below assumes that kCustomTypesMime will be first.
const char* formats[] = { kCustomTypesMime, kFileMime, kHTMLMime, kRTFMime,
kURLMime, kURLDataMime, kUnicodeMime };
for (uint32_t f = 0; f < mozilla::ArrayLength(formats); ++f) {
// check each format one at a time
@ -1251,7 +1411,11 @@ DataTransfer::CacheExternalClipboardFormats()
// if the format is supported, add an item to the array with null as
// the data. When retrieved, GetRealData will read the data.
if (supported) {
CacheExternalData(formats[f], 0, sysPrincipal);
if (f == 0) {
FillInExternalCustomTypes(0, sysPrincipal);
} else {
CacheExternalData(formats[f], 0, sysPrincipal);
}
}
}
}
@ -1269,17 +1433,17 @@ DataTransfer::FillInExternalData(TransferItem& aItem, uint32_t aIndex)
NS_ASSERTION(mEventMessage != eCut && mEventMessage != eCopy,
"clipboard event with empty data");
NS_ConvertUTF16toUTF8 utf8format(aItem.mFormat);
const char* format = utf8format.get();
if (strcmp(format, "text/plain") == 0)
format = kUnicodeMime;
else if (strcmp(format, "text/uri-list") == 0)
format = kURLDataMime;
NS_ConvertUTF16toUTF8 utf8format(aItem.mFormat);
const char* format = utf8format.get();
if (strcmp(format, "text/plain") == 0)
format = kUnicodeMime;
else if (strcmp(format, "text/uri-list") == 0)
format = kURLDataMime;
nsCOMPtr<nsITransferable> trans =
do_CreateInstance("@mozilla.org/widget/transferable;1");
if (!trans)
return;
nsCOMPtr<nsITransferable> trans =
do_CreateInstance("@mozilla.org/widget/transferable;1");
if (!trans)
return;
trans->Init(nullptr);
trans->AddDataFlavor(format);
@ -1309,33 +1473,33 @@ DataTransfer::FillInExternalData(TransferItem& aItem, uint32_t aIndex)
dragSession->GetData(trans, aIndex);
}
uint32_t length = 0;
nsCOMPtr<nsISupports> data;
trans->GetTransferData(format, getter_AddRefs(data), &length);
if (!data)
return;
uint32_t length = 0;
nsCOMPtr<nsISupports> data;
trans->GetTransferData(format, getter_AddRefs(data), &length);
if (!data)
return;
RefPtr<nsVariantCC> variant = new nsVariantCC();
RefPtr<nsVariantCC> variant = new nsVariantCC();
nsCOMPtr<nsISupportsString> supportsstr = do_QueryInterface(data);
if (supportsstr) {
nsAutoString str;
supportsstr->GetData(str);
variant->SetAsAString(str);
}
else {
nsCOMPtr<nsISupportsCString> supportscstr = do_QueryInterface(data);
if (supportscstr) {
nsAutoCString str;
supportscstr->GetData(str);
variant->SetAsACString(str);
} else {
variant->SetAsISupports(data);
}
}
aItem.mData = variant;
nsCOMPtr<nsISupportsString> supportsstr = do_QueryInterface(data);
if (supportsstr) {
nsAutoString str;
supportsstr->GetData(str);
variant->SetAsAString(str);
}
else {
nsCOMPtr<nsISupportsCString> supportscstr = do_QueryInterface(data);
if (supportscstr) {
nsAutoCString str;
supportscstr->GetData(str);
variant->SetAsACString(str);
} else {
variant->SetAsISupports(data);
}
}
aItem.mData = variant;
}
void
DataTransfer::FillAllExternalData()
@ -1352,5 +1516,67 @@ DataTransfer::FillAllExternalData()
}
}
void
DataTransfer::FillInExternalCustomTypes(uint32_t aIndex, nsIPrincipal* aPrincipal)
{
TransferItem item;
item.mFormat.AssignLiteral(kCustomTypesMime);
FillInExternalData(item, aIndex);
if (!item.mData) {
return;
}
FillInExternalCustomTypes(item.mData, aIndex, aPrincipal);
}
void
DataTransfer::FillInExternalCustomTypes(nsIVariant* aData, uint32_t aIndex, nsIPrincipal* aPrincipal)
{
char* chrs;
uint32_t len = 0;
nsresult rv = aData->GetAsStringWithSize(&len, &chrs);
if (NS_FAILED(rv)) {
return;
}
nsAutoCString str;
str.Adopt(chrs, len);
nsCOMPtr<nsIInputStream> stringStream;
NS_NewCStringInputStream(getter_AddRefs(stringStream), str);
nsCOMPtr<nsIBinaryInputStream> stream = do_CreateInstance("@mozilla.org/binaryinputstream;1");
stream->SetInputStream(stringStream);
if (!stream) {
return;
}
uint32_t type;
do {
stream->Read32(&type);
if (type == eCustomClipboardTypeId_String) {
uint32_t formatLength;
stream->Read32(&formatLength);
char* formatBytes;
stream->ReadBytes(formatLength, &formatBytes);
nsAutoString format;
format.Adopt(reinterpret_cast<char16_t*>(formatBytes), formatLength / sizeof(char16_t));
uint32_t dataLength;
stream->Read32(&dataLength);
char* dataBytes;
stream->ReadBytes(dataLength, &dataBytes);
nsAutoString data;
data.Adopt(reinterpret_cast<char16_t*>(dataBytes), dataLength / sizeof(char16_t));
RefPtr<nsVariantCC> variant = new nsVariantCC();
variant->SetAsAString(data);
SetDataWithPrincipal(format, variant, aIndex, aPrincipal);
}
} while (type != eCustomClipboardTypeId_None);
}
} // namespace dom
} // namespace mozilla

Просмотреть файл

@ -218,6 +218,13 @@ public:
uint32_t aIndex,
nsIPrincipal* aPrincipal);
// Variation of SetDataWithPrincipal with handles extracting
// kCustomTypesMime data into separate types.
void SetDataWithPrincipalFromOtherProcess(const nsAString& aFormat,
nsIVariant* aData,
uint32_t aIndex,
nsIPrincipal* aPrincipal);
// returns a weak reference to the drag image
Element* GetDragImage(int32_t* aX, int32_t* aY)
{
@ -261,6 +268,9 @@ protected:
friend class ContentParent;
void FillAllExternalData();
void FillInExternalCustomTypes(uint32_t aIndex, nsIPrincipal* aPrincipal);
void FillInExternalCustomTypes(nsIVariant* aData, uint32_t aIndex, nsIPrincipal* aPrincipal);
void MozClearDataAtHelper(const nsAString& aFormat, uint32_t aIndex,
mozilla::ErrorResult& aRv);

Просмотреть файл

@ -3222,6 +3222,9 @@ ContentChild::RecvInvokeDragSession(nsTArray<IPCDataTransfer>&& aTransfers,
if (item.data().type() == IPCDataTransferData::TnsString) {
const nsString& data = item.data().get_nsString();
variant->SetAsAString(data);
} else if (item.data().type() == IPCDataTransferData::TnsCString) {
const nsCString& data = item.data().get_nsCString();
variant->SetAsACString(data);
} else if (item.data().type() == IPCDataTransferData::TPBlobChild) {
BlobChild* blob = static_cast<BlobChild*>(item.data().get_PBlobChild());
RefPtr<BlobImpl> blobImpl = blob->GetBlobImpl();
@ -3229,9 +3232,9 @@ ContentChild::RecvInvokeDragSession(nsTArray<IPCDataTransfer>&& aTransfers,
} else {
continue;
}
dataTransfer->SetDataWithPrincipal(NS_ConvertUTF8toUTF16(item.flavor()),
variant, i,
nsContentUtils::GetSystemPrincipal());
dataTransfer->SetDataWithPrincipalFromOtherProcess(
NS_ConvertUTF8toUTF16(item.flavor()), variant, i,
nsContentUtils::GetSystemPrincipal());
}
}
session->SetDataTransfer(dataTransfer);

Просмотреть файл

@ -3142,24 +3142,27 @@ TabParent::AddInitialDnDDataTo(DataTransfer* aDataTransfer)
auto* parent = static_cast<BlobParent*>(item.data().get_PBlobParent());
RefPtr<BlobImpl> impl = parent->GetBlobImpl();
variant->SetAsISupports(impl);
} else if (item.data().type() == IPCDataTransferData::TnsCString &&
nsContentUtils::IsFlavorImage(item.flavor())) {
// An image! Get the imgIContainer for it and set it in the variant.
nsCOMPtr<imgIContainer> imageContainer;
nsresult rv =
nsContentUtils::DataTransferItemToImage(item,
getter_AddRefs(imageContainer));
if (NS_FAILED(rv)) {
continue;
} else if (item.data().type() == IPCDataTransferData::TnsCString) {
if (nsContentUtils::IsFlavorImage(item.flavor())) {
// An image! Get the imgIContainer for it and set it in the variant.
nsCOMPtr<imgIContainer> imageContainer;
nsresult rv =
nsContentUtils::DataTransferItemToImage(item,
getter_AddRefs(imageContainer));
if (NS_FAILED(rv)) {
continue;
}
variant->SetAsISupports(imageContainer);
} else {
variant->SetAsACString(item.data().get_nsCString());
}
variant->SetAsISupports(imageContainer);
}
// Using system principal here, since once the data is on parent process
// side, it can be handled as being from browser chrome or OS.
aDataTransfer->SetDataWithPrincipal(NS_ConvertUTF8toUTF16(item.flavor()),
variant, i,
nsContentUtils::GetSystemPrincipal());
aDataTransfer->SetDataWithPrincipalFromOtherProcess(NS_ConvertUTF8toUTF16(item.flavor()),
variant, i,
nsContentUtils::GetSystemPrincipal());
}
}
mInitialDataTransferItems.Clear();

Просмотреть файл

@ -453,7 +453,7 @@ function test_input_copypaste_dataTransfer_multiple() {
ok(exh, "exception occured mozClearDataAt 1");
cd.setData("text/x-moz-url", "http://www.mozilla.org");
cd.mozSetDataAt("text/x-custom", "Custom Text", 0);
cd.mozSetDataAt("text/x-custom", "Custom Text with \u0000 null", 0);
is(cd.mozItemCount, 1, "mozItemCount after set multiple types");
return false;
};
@ -479,9 +479,16 @@ function test_input_copypaste_dataTransfer_multiple() {
// disabling the following test. Enable this once bug #840101 is fixed.
if (navigator.appVersion.indexOf("Android") == -1) {
is(cd.getData("text/x-moz-url"), "http://www.mozilla.org", "paste text/x-moz-url multiple types");
is(cd.getData("text/x-custom"), "Custom Text with \u0000 null", "paste text/custom multiple types");
} else {
is(cd.getData("text/x-custom"), "", "paste text/custom multiple types");
}
// this is empty because only the built-in types are supported at the moment
is(cd.getData("text/x-custom"), "", "paste text/custom multiple types");
is(cd.getData("application/x-moz-custom-clipdata"), "", "application/x-moz-custom-clipdata is not present");
exh = false;
try { cd.setData("application/x-moz-custom-clipdata", "Some Data"); } catch (ex) { exh = true; }
ok(exh, "exception occured setData with application/x-moz-custom-clipdata");
exh = false;
try { cd.setData("text/plain", "Text on Paste"); } catch (ex) { exh = true; }

Просмотреть файл

@ -186,6 +186,31 @@ nsClipboard::TransferableFromPasteboard(nsITransferable *aTransferable, NSPasteb
free(clipboardDataPtr);
break;
}
else if (flavorStr.EqualsLiteral(kCustomTypesMime)) {
NSString* type = [cocoaPasteboard availableTypeFromArray:[NSArray arrayWithObject:kCustomTypesPboardType]];
if (!type) {
continue;
}
NSData* pasteboardData = GetDataFromPasteboard(cocoaPasteboard, type);
if (!pasteboardData) {
continue;
}
unsigned int dataLength = [pasteboardData length];
void* clipboardDataPtr = malloc(dataLength);
if (!clipboardDataPtr) {
return NS_ERROR_OUT_OF_MEMORY;
}
[pasteboardData getBytes:clipboardDataPtr];
nsCOMPtr<nsISupports> genericDataWrapper;
nsPrimitiveHelpers::CreatePrimitiveForData(flavorStr, clipboardDataPtr, dataLength,
getter_AddRefs(genericDataWrapper));
aTransferable->SetTransferData(flavorStr, genericDataWrapper, dataLength);
free(clipboardDataPtr);
}
else if (flavorStr.EqualsLiteral(kJPEGImageMime) ||
flavorStr.EqualsLiteral(kJPGImageMime) ||
flavorStr.EqualsLiteral(kPNGImageMime) ||
@ -330,7 +355,7 @@ nsClipboard::HasDataMatchingFlavors(const char** aFlavorList, uint32_t aLength,
return NS_OK;
// first see if we have data for this in our cached transferable
if (mTransferable) {
if (mTransferable) {
nsCOMPtr<nsISupportsArray> transferableFlavorList;
nsresult rv = mTransferable->FlavorsTransferableCanImport(getter_AddRefs(transferableFlavorList));
if (NS_SUCCEEDED(rv)) {
@ -367,6 +392,12 @@ nsClipboard::HasDataMatchingFlavors(const char** aFlavorList, uint32_t aLength,
*outResult = true;
break;
}
} else if (!strcmp(aFlavorList[i], kCustomTypesMime)) {
NSString* availableType = [generalPBoard availableTypeFromArray:[NSArray arrayWithObject:kCustomTypesPboardType]];
if (availableType) {
*outResult = true;
break;
}
} else if (!strcmp(aFlavorList[i], kJPEGImageMime) ||
!strcmp(aFlavorList[i], kJPGImageMime) ||
!strcmp(aFlavorList[i], kPNGImageMime) ||
@ -447,6 +478,20 @@ nsClipboard::PasteboardDictFromTransferable(nsITransferable* aTransferable)
free(data);
}
else if (flavorStr.EqualsLiteral(kCustomTypesMime)) {
void* data = nullptr;
uint32_t dataSize = 0;
nsCOMPtr<nsISupports> genericDataWrapper;
rv = aTransferable->GetTransferData(flavorStr, getter_AddRefs(genericDataWrapper), &dataSize);
nsPrimitiveHelpers::CreateDataFromPrimitive(flavorStr, genericDataWrapper, &data, dataSize);
if (data) {
NSData* nativeData = [NSData dataWithBytes:data length:dataSize];
[pasteboardOutputDict setObject:nativeData forKey:kCustomTypesPboardType];
free(data);
}
}
else if (flavorStr.EqualsLiteral(kPNGImageMime) || flavorStr.EqualsLiteral(kJPEGImageMime) ||
flavorStr.EqualsLiteral(kJPGImageMime) || flavorStr.EqualsLiteral(kGIFImageMime) ||
flavorStr.EqualsLiteral(kNativeImageMime)) {

Просмотреть файл

@ -14,6 +14,7 @@ extern NSString* const kWildcardPboardType;
extern NSString* const kCorePboardType_url;
extern NSString* const kCorePboardType_urld;
extern NSString* const kCorePboardType_urln;
extern NSString* const kCustomTypesPboardType;
class nsDragService : public nsBaseDragService
{

Просмотреть файл

@ -49,6 +49,7 @@ NSString* const kCorePboardType_url = @"CorePasteboardFlavorType 0x75726C20"; /
NSString* const kCorePboardType_urld = @"CorePasteboardFlavorType 0x75726C64"; // 'urld' desc
NSString* const kCorePboardType_urln = @"CorePasteboardFlavorType 0x75726C6E"; // 'urln' title
NSString* const kUTTypeURLName = @"public.url-name";
NSString* const kCustomTypesPboardType = @"org.mozilla.custom-clipdata";
nsDragService::nsDragService()
{
@ -110,7 +111,8 @@ static nsresult SetUpDragClipboard(nsISupportsArray* aTransferableArray)
[dragPBoard setString:(nsClipboard::WrapHtmlForSystemPasteboard(currentValue))
forType:currentKey];
}
else if (currentKey == NSTIFFPboardType) {
else if (currentKey == NSTIFFPboardType ||
currentKey == kCustomTypesPboardType) {
[dragPBoard setData:currentValue forType:currentKey];
}
else if (currentKey == NSFilesPromisePboardType ||
@ -474,6 +476,31 @@ nsDragService::GetData(nsITransferable* aTransferable, uint32_t aItemIndex)
break;
}
else if (flavorStr.EqualsLiteral(kCustomTypesMime)) {
NSString* availableType = [item availableTypeFromArray:[NSArray arrayWithObject:kCustomTypesPboardType]];
if (!availableType || !IsValidType(availableType, false)) {
continue;
}
NSData *pasteboardData = [item dataForType:availableType];
if (!pasteboardData) {
continue;
}
unsigned int dataLength = [pasteboardData length];
void* clipboardDataPtr = malloc(dataLength);
if (!clipboardDataPtr) {
return NS_ERROR_OUT_OF_MEMORY;
}
[pasteboardData getBytes:clipboardDataPtr];
nsCOMPtr<nsISupports> genericDataWrapper;
nsPrimitiveHelpers::CreatePrimitiveForData(flavorStr, clipboardDataPtr, dataLength,
getter_AddRefs(genericDataWrapper));
aTransferable->SetTransferData(flavorStr, genericDataWrapper, sizeof(nsIInputStream*));
free(clipboardDataPtr);
break;
}
NSString* pString = nil;
if (flavorStr.EqualsLiteral(kUnicodeMime)) {
@ -610,7 +637,10 @@ nsDragService::IsDataFlavorSupported(const char *aDataFlavor, bool *_retval)
type = (const NSString*)kUTTypeURLName;
} else if (dataFlavor.EqualsLiteral(kRTFMime)) {
type = (const NSString*)kUTTypeRTF;
} else if (dataFlavor.EqualsLiteral(kCustomTypesMime)) {
type = (const NSString*)kCustomTypesPboardType;
}
NSString* availableType = [globalDragPboard availableTypeFromArray:[NSArray arrayWithObjects:(id)type, nil]];
if (availableType && IsValidType(availableType, allowFileURL)) {
*_retval = true;

Просмотреть файл

@ -970,12 +970,14 @@ nsDragService::GetData(nsITransferable * aTransferable,
} // else we try one last ditch effort to find our data
if (dataFound) {
// the DOM only wants LF, so convert from MacOS line endings
// to DOM line endings.
nsLinebreakHelpers::ConvertPlatformToDOMLinebreaks(
flavorStr,
&mTargetDragData,
reinterpret_cast<int*>(&mTargetDragDataLen));
if (strcmp(flavorStr, kCustomTypesMime) != 0) {
// the DOM only wants LF, so convert from MacOS line endings
// to DOM line endings.
nsLinebreakHelpers::ConvertPlatformToDOMLinebreaks(
flavorStr,
&mTargetDragData,
reinterpret_cast<int*>(&mTargetDragDataLen));
}
// put it into the transferable.
nsCOMPtr<nsISupports> genericDataWrapper;

Просмотреть файл

@ -93,7 +93,8 @@ nsClipboardProxy::GetData(nsITransferable *aTransferable, int32_t aWhichClipboar
rv = aTransferable->SetTransferData(flavor.get(), stream, sizeof(nsISupports*));
NS_ENSURE_SUCCESS(rv, rv);
} else if (flavor.EqualsLiteral(kNativeHTMLMime) ||
flavor.EqualsLiteral(kRTFMime)) {
flavor.EqualsLiteral(kRTFMime) ||
flavor.EqualsLiteral(kCustomTypesMime)) {
nsCOMPtr<nsISupportsCString> dataWrapper =
do_CreateInstance(NS_SUPPORTS_CSTRING_CONTRACTID, &rv);
NS_ENSURE_SUCCESS(rv, rv);

Просмотреть файл

@ -49,6 +49,8 @@ interface nsIDOMNode;
// a synthetic flavor, put into the transferable once we know the destination directory of a file drag
#define kFilePromiseDirectoryMime "application/x-moz-file-promise-dir"
#define kCustomTypesMime "application/x-moz-custom-clipdata"
%}

Просмотреть файл

@ -48,7 +48,7 @@ nsPrimitiveHelpers :: CreatePrimitiveForData ( const char* aFlavor, const void*
return;
if ( strcmp(aFlavor,kTextMime) == 0 || strcmp(aFlavor,kNativeHTMLMime) == 0 ||
strcmp(aFlavor,kRTFMime) == 0) {
strcmp(aFlavor,kRTFMime) == 0 || strcmp(aFlavor,kCustomTypesMime) == 0) {
nsCOMPtr<nsISupportsCString> primitive =
do_CreateInstance(NS_SUPPORTS_CSTRING_CONTRACTID);
if ( primitive ) {
@ -133,7 +133,7 @@ nsPrimitiveHelpers :: CreateDataFromPrimitive ( const char* aFlavor, nsISupports
*aDataBuff = nullptr;
if ( strcmp(aFlavor,kTextMime) == 0 ) {
if ( strcmp(aFlavor,kTextMime) == 0 || strcmp(aFlavor,kCustomTypesMime) == 0) {
nsCOMPtr<nsISupportsCString> plainText ( do_QueryInterface(aPrimitive) );
if ( plainText ) {
nsAutoCString data;

Просмотреть файл

@ -42,6 +42,7 @@ PRLogModuleInfo* gWin32ClipboardLog = nullptr;
// oddly, this isn't in the MSVC headers anywhere.
UINT nsClipboard::CF_HTML = ::RegisterClipboardFormatW(L"HTML Format");
UINT nsClipboard::CF_CUSTOMTYPES = ::RegisterClipboardFormatW(L"application/x-moz-custom-clipdata");
//-------------------------------------------------------------------------
@ -108,6 +109,8 @@ UINT nsClipboard::GetFormat(const char* aMimeStr, bool aMapHTMLMime)
else if (strcmp(aMimeStr, kNativeHTMLMime) == 0 ||
aMapHTMLMime && strcmp(aMimeStr, kHTMLMime) == 0)
format = CF_HTML;
else if (strcmp(aMimeStr, kCustomTypesMime) == 0)
format = CF_CUSTOMTYPES;
else
format = ::RegisterClipboardFormatW(NS_ConvertASCIItoUTF16(aMimeStr).get());
@ -534,6 +537,9 @@ nsresult nsClipboard::GetNativeDataOffClipboard(IDataObject * aDataObject, UINT
// do that in FindPlatformHTML(). For now, return the allocLen. This
// case is mostly to ensure we don't try to call strlen on the buffer.
*aLen = allocLen;
} else if (fe.cfFormat == CF_CUSTOMTYPES) {
// Binary data
*aLen = allocLen;
} else if (fe.cfFormat == preferredDropEffect) {
// As per the MSDN doc entitled: "Shell Clipboard Formats"
// CFSTR_PREFERREDDROPEFFECT should return a DWORD
@ -682,16 +688,19 @@ nsresult nsClipboard::GetDataFromDataObject(IDataObject * aDataObject,
NS_IF_RELEASE(imageStream);
}
else {
// we probably have some form of text. The DOM only wants LF, so convert from Win32 line
// endings to DOM line endings.
int32_t signedLen = static_cast<int32_t>(dataLen);
nsLinebreakHelpers::ConvertPlatformToDOMLinebreaks ( flavorStr, &data, &signedLen );
dataLen = signedLen;
// Treat custom types as a string of bytes.
if (strcmp(flavorStr, kCustomTypesMime) != 0) {
// we probably have some form of text. The DOM only wants LF, so convert from Win32 line
// endings to DOM line endings.
int32_t signedLen = static_cast<int32_t>(dataLen);
nsLinebreakHelpers::ConvertPlatformToDOMLinebreaks ( flavorStr, &data, &signedLen );
dataLen = signedLen;
if (strcmp(flavorStr, kRTFMime) == 0) {
// RTF on Windows is known to sometimes deliver an extra null byte.
if (dataLen > 0 && static_cast<char*>(data)[dataLen - 1] == '\0')
dataLen--;
if (strcmp(flavorStr, kRTFMime) == 0) {
// RTF on Windows is known to sometimes deliver an extra null byte.
if (dataLen > 0 && static_cast<char*>(data)[dataLen - 1] == '\0')
dataLen--;
}
}
nsPrimitiveHelpers::CreatePrimitiveForData ( flavorStr, data, dataLen, getter_AddRefs(genericDataWrapper) );

Просмотреть файл

@ -60,6 +60,7 @@ public:
static UINT GetFormat(const char* aMimeStr, bool aMapHTMLMime = true);
static UINT CF_HTML;
static UINT CF_CUSTOMTYPES;
protected:
NS_IMETHOD SetNativeClipboardData ( int32_t aWhichClipboard ) override;

Просмотреть файл

@ -1328,7 +1328,7 @@ HRESULT nsDataObj::GetText(const nsACString & aDataFlavor, FORMATETC& aFE, STGME
return S_OK;
}
}
else {
else if ( aFE.cfFormat != nsClipboard::CF_CUSTOMTYPES ) {
// we assume that any data that isn't caught above is unicode. This may
// be an erroneous assumption, but is true so far.
allocLen += sizeof(char16_t);