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 "nsIClipboard.h"
#include "nsContentUtils.h" #include "nsContentUtils.h"
#include "nsIContent.h" #include "nsIContent.h"
#include "nsIBinaryInputStream.h"
#include "nsIBinaryOutputStream.h"
#include "nsIStorageStream.h"
#include "nsStringStream.h"
#include "nsCRT.h" #include "nsCRT.h"
#include "nsIScriptObjectPrincipal.h" #include "nsIScriptObjectPrincipal.h"
#include "nsIScriptContext.h" #include "nsIScriptContext.h"
@ -80,6 +84,12 @@ const char DataTransfer::sEffects[8][9] = {
"none", "copy", "move", "copyMove", "link", "copyLink", "linkMove", "all" "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, DataTransfer::DataTransfer(nsISupports* aParent, EventMessage aEventMessage,
bool aIsExternal, int32_t aClipboardType) bool aIsExternal, int32_t aClipboardType)
: mParent(aParent) : mParent(aParent)
@ -710,6 +720,11 @@ DataTransfer::SetDataAtInternal(const nsAString& aFormat, nsIVariant* aData,
return NS_ERROR_DOM_INDEX_SIZE_ERR; 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 // 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. // promises as well which are used internally for drags to the desktop.
if (!nsContentUtils::IsSystemPrincipal(aSubjectPrincipal)) { if (!nsContentUtils::IsSystemPrincipal(aSubjectPrincipal)) {
@ -984,29 +999,147 @@ DataTransfer::GetTransferable(uint32_t aIndex, nsILoadContext* aLoadContext)
} }
transferable->Init(aLoadContext); transferable->Init(aLoadContext);
nsCOMPtr<nsIStorageStream> storageStream;
nsCOMPtr<nsIBinaryOutputStream> stream;
bool added = false; bool added = false;
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++) { for (uint32_t f = 0; f < count; f++) {
const TransferItem& formatitem = item[f]; const TransferItem& formatitem = item[f];
if (!formatitem.mData) { // skip empty items if (!formatitem.mData) { // skip empty items
continue; continue;
} }
uint32_t length; // 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; nsCOMPtr<nsISupports> convertedData;
if (!ConvertFromVariant(formatitem.mData, getter_AddRefs(convertedData), &length)) {
if (handlingCustomFormats) {
if (!ConvertFromVariant(formatitem.mData, getter_AddRefs(convertedData), &lengthInBytes)) {
continue; continue;
} }
// the underlying drag code uses text/unicode, so use that instead of text/plain // 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; const char* format;
NS_ConvertUTF16toUTF8 utf8format(formatitem.mFormat); NS_ConvertUTF16toUTF8 utf8format(formatitem.mFormat);
if (utf8format.EqualsLiteral("text/plain")) { if (utf8format.EqualsLiteral(kTextMime)) {
format = kUnicodeMime; format = kUnicodeMime;
} else { } else {
format = utf8format.get(); format = utf8format.get();
} }
// if a converter is set for a format, set the converter for the // If a converter is set for a format, set the converter for the
// transferable and don't add the item // transferable and don't add the item
nsCOMPtr<nsIFormatConverter> converter = do_QueryInterface(convertedData); nsCOMPtr<nsIFormatConverter> converter = do_QueryInterface(convertedData);
if (converter) { if (converter) {
@ -1015,13 +1148,17 @@ DataTransfer::GetTransferable(uint32_t aIndex, nsILoadContext* aLoadContext)
continue; continue;
} }
nsresult rv = transferable->SetTransferData(format, convertedData, length); nsresult rv = transferable->SetTransferData(format, convertedData, lengthInBytes);
if (NS_FAILED(rv)) { if (NS_FAILED(rv)) {
return nullptr; return nullptr;
} }
added = true; added = true;
} }
}
handlingCustomFormats = !handlingCustomFormats;
} while (!handlingCustomFormats);
// only return the transferable if data was successfully added to it // only return the transferable if data was successfully added to it
if (added) { if (added) {
@ -1152,6 +1289,19 @@ DataTransfer::SetDataWithPrincipal(const nsAString& aFormat,
return NS_OK; 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 void
DataTransfer::GetRealFormat(const nsAString& aInFormat, nsAString& aOutFormat) 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 // 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 // all platforms, so just check for the types that can actually be imported
// XXXndeakin there are some other formats but those are platform specific. // 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; uint32_t count;
dragSession->GetNumDropItems(&count); dragSession->GetNumDropItems(&count);
for (uint32_t c = 0; c < count; c++) { 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++) { for (uint32_t f = 0; f < ArrayLength(formats); f++) {
// IsDataFlavorSupported doesn't take an index as an argument and just // IsDataFlavorSupported doesn't take an index as an argument and just
// checks if any of the items support a particular flavor, even though // checks if any of the items support a particular flavor, even though
@ -1241,8 +1399,10 @@ DataTransfer::CacheExternalClipboardFormats()
ssm->GetSystemPrincipal(getter_AddRefs(sysPrincipal)); ssm->GetSystemPrincipal(getter_AddRefs(sysPrincipal));
// there isn't a way to get a list of the formats that might be available on // 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 // all platforms, so just check for the types that can actually be imported.
const char* formats[] = { kFileMime, kHTMLMime, kRTFMime, kURLMime, kURLDataMime, kUnicodeMime }; // 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) { for (uint32_t f = 0; f < mozilla::ArrayLength(formats); ++f) {
// check each format one at a time // check each format one at a time
@ -1251,9 +1411,13 @@ DataTransfer::CacheExternalClipboardFormats()
// if the format is supported, add an item to the array with null as // if the format is supported, add an item to the array with null as
// the data. When retrieved, GetRealData will read the data. // the data. When retrieved, GetRealData will read the data.
if (supported) { if (supported) {
if (f == 0) {
FillInExternalCustomTypes(0, sysPrincipal);
} else {
CacheExternalData(formats[f], 0, sysPrincipal); CacheExternalData(formats[f], 0, sysPrincipal);
} }
} }
}
} }
void void
@ -1335,7 +1499,7 @@ DataTransfer::FillInExternalData(TransferItem& aItem, uint32_t aIndex)
} }
aItem.mData = variant; aItem.mData = variant;
} }
void void
DataTransfer::FillAllExternalData() 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 dom
} // namespace mozilla } // namespace mozilla

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

@ -218,6 +218,13 @@ public:
uint32_t aIndex, uint32_t aIndex,
nsIPrincipal* aPrincipal); 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 // returns a weak reference to the drag image
Element* GetDragImage(int32_t* aX, int32_t* aY) Element* GetDragImage(int32_t* aX, int32_t* aY)
{ {
@ -261,6 +268,9 @@ protected:
friend class ContentParent; friend class ContentParent;
void FillAllExternalData(); 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, void MozClearDataAtHelper(const nsAString& aFormat, uint32_t aIndex,
mozilla::ErrorResult& aRv); mozilla::ErrorResult& aRv);

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

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

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

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

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

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

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

@ -186,6 +186,31 @@ nsClipboard::TransferableFromPasteboard(nsITransferable *aTransferable, NSPasteb
free(clipboardDataPtr); free(clipboardDataPtr);
break; 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) || else if (flavorStr.EqualsLiteral(kJPEGImageMime) ||
flavorStr.EqualsLiteral(kJPGImageMime) || flavorStr.EqualsLiteral(kJPGImageMime) ||
flavorStr.EqualsLiteral(kPNGImageMime) || flavorStr.EqualsLiteral(kPNGImageMime) ||
@ -367,6 +392,12 @@ nsClipboard::HasDataMatchingFlavors(const char** aFlavorList, uint32_t aLength,
*outResult = true; *outResult = true;
break; 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) || } else if (!strcmp(aFlavorList[i], kJPEGImageMime) ||
!strcmp(aFlavorList[i], kJPGImageMime) || !strcmp(aFlavorList[i], kJPGImageMime) ||
!strcmp(aFlavorList[i], kPNGImageMime) || !strcmp(aFlavorList[i], kPNGImageMime) ||
@ -447,6 +478,20 @@ nsClipboard::PasteboardDictFromTransferable(nsITransferable* aTransferable)
free(data); 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) || else if (flavorStr.EqualsLiteral(kPNGImageMime) || flavorStr.EqualsLiteral(kJPEGImageMime) ||
flavorStr.EqualsLiteral(kJPGImageMime) || flavorStr.EqualsLiteral(kGIFImageMime) || flavorStr.EqualsLiteral(kJPGImageMime) || flavorStr.EqualsLiteral(kGIFImageMime) ||
flavorStr.EqualsLiteral(kNativeImageMime)) { flavorStr.EqualsLiteral(kNativeImageMime)) {

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

@ -14,6 +14,7 @@ extern NSString* const kWildcardPboardType;
extern NSString* const kCorePboardType_url; extern NSString* const kCorePboardType_url;
extern NSString* const kCorePboardType_urld; extern NSString* const kCorePboardType_urld;
extern NSString* const kCorePboardType_urln; extern NSString* const kCorePboardType_urln;
extern NSString* const kCustomTypesPboardType;
class nsDragService : public nsBaseDragService 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_urld = @"CorePasteboardFlavorType 0x75726C64"; // 'urld' desc
NSString* const kCorePboardType_urln = @"CorePasteboardFlavorType 0x75726C6E"; // 'urln' title NSString* const kCorePboardType_urln = @"CorePasteboardFlavorType 0x75726C6E"; // 'urln' title
NSString* const kUTTypeURLName = @"public.url-name"; NSString* const kUTTypeURLName = @"public.url-name";
NSString* const kCustomTypesPboardType = @"org.mozilla.custom-clipdata";
nsDragService::nsDragService() nsDragService::nsDragService()
{ {
@ -110,7 +111,8 @@ static nsresult SetUpDragClipboard(nsISupportsArray* aTransferableArray)
[dragPBoard setString:(nsClipboard::WrapHtmlForSystemPasteboard(currentValue)) [dragPBoard setString:(nsClipboard::WrapHtmlForSystemPasteboard(currentValue))
forType:currentKey]; forType:currentKey];
} }
else if (currentKey == NSTIFFPboardType) { else if (currentKey == NSTIFFPboardType ||
currentKey == kCustomTypesPboardType) {
[dragPBoard setData:currentValue forType:currentKey]; [dragPBoard setData:currentValue forType:currentKey];
} }
else if (currentKey == NSFilesPromisePboardType || else if (currentKey == NSFilesPromisePboardType ||
@ -474,6 +476,31 @@ nsDragService::GetData(nsITransferable* aTransferable, uint32_t aItemIndex)
break; 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; NSString* pString = nil;
if (flavorStr.EqualsLiteral(kUnicodeMime)) { if (flavorStr.EqualsLiteral(kUnicodeMime)) {
@ -610,7 +637,10 @@ nsDragService::IsDataFlavorSupported(const char *aDataFlavor, bool *_retval)
type = (const NSString*)kUTTypeURLName; type = (const NSString*)kUTTypeURLName;
} else if (dataFlavor.EqualsLiteral(kRTFMime)) { } else if (dataFlavor.EqualsLiteral(kRTFMime)) {
type = (const NSString*)kUTTypeRTF; type = (const NSString*)kUTTypeRTF;
} else if (dataFlavor.EqualsLiteral(kCustomTypesMime)) {
type = (const NSString*)kCustomTypesPboardType;
} }
NSString* availableType = [globalDragPboard availableTypeFromArray:[NSArray arrayWithObjects:(id)type, nil]]; NSString* availableType = [globalDragPboard availableTypeFromArray:[NSArray arrayWithObjects:(id)type, nil]];
if (availableType && IsValidType(availableType, allowFileURL)) { if (availableType && IsValidType(availableType, allowFileURL)) {
*_retval = true; *_retval = true;

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

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

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

@ -93,7 +93,8 @@ nsClipboardProxy::GetData(nsITransferable *aTransferable, int32_t aWhichClipboar
rv = aTransferable->SetTransferData(flavor.get(), stream, sizeof(nsISupports*)); rv = aTransferable->SetTransferData(flavor.get(), stream, sizeof(nsISupports*));
NS_ENSURE_SUCCESS(rv, rv); NS_ENSURE_SUCCESS(rv, rv);
} else if (flavor.EqualsLiteral(kNativeHTMLMime) || } else if (flavor.EqualsLiteral(kNativeHTMLMime) ||
flavor.EqualsLiteral(kRTFMime)) { flavor.EqualsLiteral(kRTFMime) ||
flavor.EqualsLiteral(kCustomTypesMime)) {
nsCOMPtr<nsISupportsCString> dataWrapper = nsCOMPtr<nsISupportsCString> dataWrapper =
do_CreateInstance(NS_SUPPORTS_CSTRING_CONTRACTID, &rv); do_CreateInstance(NS_SUPPORTS_CSTRING_CONTRACTID, &rv);
NS_ENSURE_SUCCESS(rv, 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 // 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 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; return;
if ( strcmp(aFlavor,kTextMime) == 0 || strcmp(aFlavor,kNativeHTMLMime) == 0 || if ( strcmp(aFlavor,kTextMime) == 0 || strcmp(aFlavor,kNativeHTMLMime) == 0 ||
strcmp(aFlavor,kRTFMime) == 0) { strcmp(aFlavor,kRTFMime) == 0 || strcmp(aFlavor,kCustomTypesMime) == 0) {
nsCOMPtr<nsISupportsCString> primitive = nsCOMPtr<nsISupportsCString> primitive =
do_CreateInstance(NS_SUPPORTS_CSTRING_CONTRACTID); do_CreateInstance(NS_SUPPORTS_CSTRING_CONTRACTID);
if ( primitive ) { if ( primitive ) {
@ -133,7 +133,7 @@ nsPrimitiveHelpers :: CreateDataFromPrimitive ( const char* aFlavor, nsISupports
*aDataBuff = nullptr; *aDataBuff = nullptr;
if ( strcmp(aFlavor,kTextMime) == 0 ) { if ( strcmp(aFlavor,kTextMime) == 0 || strcmp(aFlavor,kCustomTypesMime) == 0) {
nsCOMPtr<nsISupportsCString> plainText ( do_QueryInterface(aPrimitive) ); nsCOMPtr<nsISupportsCString> plainText ( do_QueryInterface(aPrimitive) );
if ( plainText ) { if ( plainText ) {
nsAutoCString data; nsAutoCString data;

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

@ -42,6 +42,7 @@ PRLogModuleInfo* gWin32ClipboardLog = nullptr;
// oddly, this isn't in the MSVC headers anywhere. // oddly, this isn't in the MSVC headers anywhere.
UINT nsClipboard::CF_HTML = ::RegisterClipboardFormatW(L"HTML Format"); 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 || else if (strcmp(aMimeStr, kNativeHTMLMime) == 0 ||
aMapHTMLMime && strcmp(aMimeStr, kHTMLMime) == 0) aMapHTMLMime && strcmp(aMimeStr, kHTMLMime) == 0)
format = CF_HTML; format = CF_HTML;
else if (strcmp(aMimeStr, kCustomTypesMime) == 0)
format = CF_CUSTOMTYPES;
else else
format = ::RegisterClipboardFormatW(NS_ConvertASCIItoUTF16(aMimeStr).get()); 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 // 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. // case is mostly to ensure we don't try to call strlen on the buffer.
*aLen = allocLen; *aLen = allocLen;
} else if (fe.cfFormat == CF_CUSTOMTYPES) {
// Binary data
*aLen = allocLen;
} else if (fe.cfFormat == preferredDropEffect) { } else if (fe.cfFormat == preferredDropEffect) {
// As per the MSDN doc entitled: "Shell Clipboard Formats" // As per the MSDN doc entitled: "Shell Clipboard Formats"
// CFSTR_PREFERREDDROPEFFECT should return a DWORD // CFSTR_PREFERREDDROPEFFECT should return a DWORD
@ -682,6 +688,8 @@ nsresult nsClipboard::GetDataFromDataObject(IDataObject * aDataObject,
NS_IF_RELEASE(imageStream); NS_IF_RELEASE(imageStream);
} }
else { else {
// 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 // we probably have some form of text. The DOM only wants LF, so convert from Win32 line
// endings to DOM line endings. // endings to DOM line endings.
int32_t signedLen = static_cast<int32_t>(dataLen); int32_t signedLen = static_cast<int32_t>(dataLen);
@ -693,6 +701,7 @@ nsresult nsClipboard::GetDataFromDataObject(IDataObject * aDataObject,
if (dataLen > 0 && static_cast<char*>(data)[dataLen - 1] == '\0') if (dataLen > 0 && static_cast<char*>(data)[dataLen - 1] == '\0')
dataLen--; dataLen--;
} }
}
nsPrimitiveHelpers::CreatePrimitiveForData ( flavorStr, data, dataLen, getter_AddRefs(genericDataWrapper) ); nsPrimitiveHelpers::CreatePrimitiveForData ( flavorStr, data, dataLen, getter_AddRefs(genericDataWrapper) );
free(data); free(data);

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

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

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

@ -1328,7 +1328,7 @@ HRESULT nsDataObj::GetText(const nsACString & aDataFlavor, FORMATETC& aFE, STGME
return S_OK; 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 // we assume that any data that isn't caught above is unicode. This may
// be an erroneous assumption, but is true so far. // be an erroneous assumption, but is true so far.
allocLen += sizeof(char16_t); allocLen += sizeof(char16_t);