mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-08 02:14:43 +00:00
Bug 860857, support custom datatransfer types using a special type, r=smaug,jmathies,mstange
This commit is contained in:
parent
d614e66d46
commit
a030ec3ce6
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user