author | Neil Deakin <neil@mozilla.com> |
Thu, 21 Apr 2016 14:11:14 -0400 | |
changeset 294365 | 4cbc83f4c4b1d7cd3bf9758247dce1f54318fb62 |
parent 294364 | eb1d405b1239f342187201225a6cac0ff21440c2 |
child 294366 | 2747cac2de2fcfd3233930a10e4fa560b3376b60 |
push id | 30203 |
push user | cbook@mozilla.com |
push date | Fri, 22 Apr 2016 13:56:37 +0000 |
treeherder | mozilla-central@fc15477ce628 [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | smaug, jmathies, mstange |
bugs | 860857 |
milestone | 48.0a1 |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
--- a/dom/events/DataTransfer.cpp +++ b/dom/events/DataTransfer.cpp @@ -13,16 +13,20 @@ #include "nsISupportsPrimitives.h" #include "nsIScriptSecurityManager.h" #include "mozilla/dom/DOMStringList.h" #include "nsError.h" #include "nsIDragService.h" #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" #include "nsIDocument.h" #include "nsIScriptGlobalObject.h" #include "nsVariant.h" #include "mozilla/dom/ContentChild.h" #include "mozilla/dom/DataTransferBinding.h" @@ -75,16 +79,22 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION( NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMDataTransfer) NS_INTERFACE_MAP_END // the size of the array 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) , mDropEffect(nsIDragService::DRAGDROP_ACTION_NONE) , mEffectAllowed(nsIDragService::DRAGDROP_ACTION_UNINITIALIZED) , mEventMessage(aEventMessage) , mCursorState(false) , mReadOnly(true) @@ -705,16 +715,21 @@ DataTransfer::SetDataAtInternal(const ns // Only the first item is valid for clipboard events if (aIndex > 0 && (mEventMessage == eCut || mEventMessage == eCopy || mEventMessage == ePaste)) { 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)) { if (aFormat.EqualsLiteral("application/x-moz-file-promise") || aFormat.EqualsLiteral("application/x-moz-file")) { return NS_ERROR_DOM_SECURITY_ERR; } @@ -979,54 +994,176 @@ DataTransfer::GetTransferable(uint32_t a nsCOMPtr<nsITransferable> transferable = do_CreateInstance("@mozilla.org/widget/transferable;1"); if (!transferable) { return nullptr; } 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); - uint32_t length; - nsCOMPtr<nsISupports> convertedData; - if (!ConvertFromVariant(formatitem.mData, getter_AddRefs(convertedData), &length)) { - continue; + 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; + } } - // 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) { return transferable.forget(); } return nullptr; } @@ -1148,16 +1285,29 @@ DataTransfer::SetDataWithPrincipal(const formatitem->mFormat = format; formatitem->mPrincipal = aPrincipal; formatitem->mData = aData; 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) { // treat text/unicode as equivalent to text/plain nsAutoString lowercaseFormat; nsContentUtils::ASCIIToLower(aInFormat, lowercaseFormat); if (lowercaseFormat.EqualsLiteral("text") || lowercaseFormat.EqualsLiteral("text/unicode")) aOutFormat.AssignLiteral("text/plain"); else if (lowercaseFormat.EqualsLiteral("url")) @@ -1195,21 +1345,29 @@ DataTransfer::CacheExternalDragFormats() // make sure that the system principal is used for external drags nsIScriptSecurityManager* ssm = nsContentUtils::GetSecurityManager(); nsCOMPtr<nsIPrincipal> sysPrincipal; 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 // 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 // the GetData method does take an index. Here, we just assume that // every item being dragged has the same set of flavors. bool supported; dragSession->IsDataFlavorSupported(formats[f], &supported); // if the format is supported, add an item to the array with null as @@ -1236,27 +1394,33 @@ DataTransfer::CacheExternalClipboardForm return; } nsIScriptSecurityManager* ssm = nsContentUtils::GetSecurityManager(); nsCOMPtr<nsIPrincipal> sysPrincipal; 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 bool supported; clipboard->HasDataMatchingFlavors(&(formats[f]), 1, mClipboardType, &supported); // 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); + } } } } void DataTransfer::FillInExternalData(TransferItem& aItem, uint32_t aIndex) { NS_PRECONDITION(mIsExternal, "Not an external data transfer"); @@ -1264,27 +1428,27 @@ DataTransfer::FillInExternalData(Transfe if (aItem.mData) { return; } // only drag and paste events should be calling FillInExternalData 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); if (mEventMessage == ePaste) { MOZ_ASSERT(aIndex == 0, "index in clipboard must be 0"); nsCOMPtr<nsIClipboard> clipboard = do_GetService("@mozilla.org/widget/clipboard;1"); @@ -1304,53 +1468,115 @@ DataTransfer::FillInExternalData(Transfe nsCOMPtr<nsIDOMDocument> domDoc; dragSession->GetSourceDocument(getter_AddRefs(domDoc)); MOZ_ASSERT(!domDoc); #endif 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); + 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); } - else { - nsCOMPtr<nsISupportsCString> supportscstr = do_QueryInterface(data); - if (supportscstr) { - nsAutoCString str; - supportscstr->GetData(str); - variant->SetAsACString(str); - } else { - variant->SetAsISupports(data); - } - } + } - aItem.mData = variant; - } + aItem.mData = variant; +} void DataTransfer::FillAllExternalData() { if (mIsExternal) { for (uint32_t i = 0; i < mItems.Length(); ++i) { nsTArray<TransferItem>& itemArray = mItems[i]; for (uint32_t j = 0; j < itemArray.Length(); ++j) { if (!itemArray[j].mData) { FillInExternalData(itemArray[j], i); } } } } } +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
--- a/dom/events/DataTransfer.h +++ b/dom/events/DataTransfer.h @@ -213,16 +213,23 @@ public: // Similar to SetData except also specifies the principal to store. // aData may be null when called from CacheExternalDragFormats or // CacheExternalClipboardFormats. nsresult SetDataWithPrincipal(const nsAString& aFormat, nsIVariant* aData, 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) { *aX = mDragImageX; *aY = mDragImageY; return mDragImage; } @@ -256,16 +263,19 @@ protected: nsresult GetDataAtInternal(const nsAString& aFormat, uint32_t aIndex, nsIPrincipal* aSubjectPrincipal, nsIVariant** aData); nsresult SetDataAtInternal(const nsAString& aFormat, nsIVariant* aData, uint32_t aIndex, nsIPrincipal* aSubjectPrincipal); 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); nsCOMPtr<nsISupports> mParent; // the drop effect and effect allowed uint32_t mDropEffect;
--- a/dom/ipc/ContentChild.cpp +++ b/dom/ipc/ContentChild.cpp @@ -3217,26 +3217,29 @@ ContentChild::RecvInvokeDragSession(nsTA for (uint32_t i = 0; i < aTransfers.Length(); ++i) { auto& items = aTransfers[i].items(); for (uint32_t j = 0; j < items.Length(); ++j) { const IPCDataTransferItem& item = items[j]; RefPtr<nsVariantCC> variant = new nsVariantCC(); 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(); variant->SetAsISupports(blobImpl); } 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); } } return true; }
--- a/dom/ipc/TabParent.cpp +++ b/dom/ipc/TabParent.cpp @@ -3137,34 +3137,37 @@ TabParent::AddInitialDnDDataTo(DataTrans new nsContentAreaDragDropDataProvider(); variant->SetAsISupports(flavorDataProvider); } else if (item.data().type() == IPCDataTransferData::TnsString) { variant->SetAsAString(item.data().get_nsString()); } else if (item.data().type() == IPCDataTransferData::TPBlobParent) { 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(); } void TabParent::TakeDragVisualization(RefPtr<mozilla::gfx::SourceSurface>& aSurface, int32_t& aDragAreaX, int32_t& aDragAreaY)
--- a/dom/tests/mochitest/general/test_clipboard_events.html +++ b/dom/tests/mochitest/general/test_clipboard_events.html @@ -448,17 +448,17 @@ function test_input_copypaste_dataTransf exh = false; try { cd.mozGetDataAt("text/plain", 1); } catch (ex) { exh = true; } ok(exh, "exception occured mozGetDataAt 1"); exh = false; try { cd.mozClearDataAt("text/plain", 1); } catch (ex) { exh = true; } 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; }; try { selectContentInput(); synthesizeKey("c", {accelKey: 1}); } @@ -474,19 +474,26 @@ function test_input_copypaste_dataTransf var cd = event.clipboardData; is(cd.mozItemCount, 1, "paste after copy multiple types mozItemCount"); is(cd.getData("text/plain"), "would be a phrase", "paste text/plain multiple types"); // Firefox for Android's clipboard code doesn't handle x-moz-url. Therefore // 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; } ok(exh, "exception occured setData on paste"); is(cd.getData("text/plain"), "would be a phrase", "text/plain data unchanged"); }; try {
--- a/widget/cocoa/nsClipboard.mm +++ b/widget/cocoa/nsClipboard.mm @@ -181,16 +181,41 @@ nsClipboard::TransferableFromPasteboard( nsCOMPtr<nsISupports> genericDataWrapper; nsPrimitiveHelpers::CreatePrimitiveForData(flavorStr, clipboardDataPtrNoBOM, dataLength, getter_AddRefs(genericDataWrapper)); aTransferable->SetTransferData(flavorStr, genericDataWrapper, dataLength); 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) || flavorStr.EqualsLiteral(kGIFImageMime)) { // Figure out if there's data on the pasteboard we can grab (sanity check) NSString *type = [cocoaPasteboard availableTypeFromArray:[NSArray arrayWithObjects:IMAGE_PASTEBOARD_TYPES]]; if (!type) continue; @@ -325,17 +350,17 @@ nsClipboard::HasDataMatchingFlavors(cons NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT; *outResult = false; if ((aWhichClipboard != kGlobalClipboard) || !aFlavorList) 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)) { uint32_t transferableFlavorCount; transferableFlavorList->Count(&transferableFlavorCount); for (uint32_t j = 0; j < transferableFlavorCount; j++) { nsCOMPtr<nsISupports> transferableFlavorSupports; transferableFlavorList->GetElementAt(j, getter_AddRefs(transferableFlavorSupports)); @@ -362,16 +387,22 @@ nsClipboard::HasDataMatchingFlavors(cons NSString *pboardType = nil; if (nsClipboard::IsStringType(mimeType, &pboardType)) { NSString* availableType = [generalPBoard availableTypeFromArray:[NSArray arrayWithObject:pboardType]]; if (availableType && [availableType isEqualToString:pboardType]) { *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) || !strcmp(aFlavorList[i], kGIFImageMime)) { NSString* availableType = [generalPBoard availableTypeFromArray: [NSArray arrayWithObjects:IMAGE_PASTEBOARD_TYPES]]; if (availableType) { *outResult = true; @@ -442,16 +473,30 @@ nsClipboard::PasteboardDictFromTransfera // be nice to Carbon apps, normalize the receiver's contents using Form C. nativeString = [nativeString precomposedStringWithCanonicalMapping]; [pasteboardOutputDict setObject:nativeString forKey:pboardType]; 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)) { uint32_t dataSize = 0; nsCOMPtr<nsISupports> transferSupports; aTransferable->GetTransferData(flavorStr, getter_AddRefs(transferSupports), &dataSize); nsCOMPtr<nsISupportsInterfacePointer> ptrPrimitive(do_QueryInterface(transferSupports)); if (!ptrPrimitive)
--- a/widget/cocoa/nsDragService.h +++ b/widget/cocoa/nsDragService.h @@ -9,16 +9,17 @@ #include "nsBaseDragService.h" #include <Cocoa/Cocoa.h> 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 { public: nsDragService(); // nsBaseDragService virtual nsresult InvokeDragSessionImpl(nsISupportsArray* anArrayTransferables,
--- a/widget/cocoa/nsDragService.mm +++ b/widget/cocoa/nsDragService.mm @@ -44,16 +44,17 @@ extern bool gUserCancelledDrag; // file destination callback. nsISupportsArray *gDraggedTransferables = nullptr; NSString* const kWildcardPboardType = @"MozillaWildcard"; NSString* const kCorePboardType_url = @"CorePasteboardFlavorType 0x75726C20"; // 'url ' url 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() { mNativeDragView = nil; mNativeDragEvent = nil; EnsureLogInitialized(); } @@ -105,17 +106,18 @@ static nsresult SetUpDragClipboard(nsISu currentKey == kCorePboardType_urld || currentKey == kCorePboardType_urln) { [dragPBoard setString:currentValue forType:currentKey]; } else if (currentKey == NSHTMLPboardType) { [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 || currentKey == NSFilenamesPboardType) { [dragPBoard setPropertyList:currentValue forType:currentKey]; } } } @@ -469,16 +471,41 @@ nsDragService::GetData(nsITransferable* free(clipboardDataPtr); if (NS_FAILED(rv)) continue; aTransferable->SetTransferData(flavorStr, file, dataLength); 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)) { pString = GetStringForType(item, (const NSString*)kUTTypeUTF8PlainText); } else if (flavorStr.EqualsLiteral(kHTMLMime)) { pString = GetStringForType(item, (const NSString*)kUTTypeHTML); } else if (flavorStr.EqualsLiteral(kURLMime)) { pString = GetStringForType(item, (const NSString*)kUTTypeURL); @@ -605,17 +632,20 @@ nsDragService::IsDataFlavorSupported(con type = (const NSString*)kUTTypeHTML; } else if (dataFlavor.EqualsLiteral(kURLMime) || dataFlavor.EqualsLiteral(kURLDataMime)) { type = (const NSString*)kUTTypeURL; } else if (dataFlavor.EqualsLiteral(kURLDescriptionMime)) { 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; } return NS_OK; NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
--- a/widget/gtk/nsDragService.cpp +++ b/widget/gtk/nsDragService.cpp @@ -965,22 +965,24 @@ nsDragService::GetData(nsITransferable * ("failed to get _NETSCAPE_URL data\n")); } } } } // 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; nsPrimitiveHelpers::CreatePrimitiveForData(flavorStr, mTargetDragData, mTargetDragDataLen, getter_AddRefs(genericDataWrapper)); aTransferable->SetTransferData(flavorStr, genericDataWrapper,
--- a/widget/nsClipboardProxy.cpp +++ b/widget/nsClipboardProxy.cpp @@ -88,17 +88,18 @@ nsClipboardProxy::GetData(nsITransferabl flavor.EqualsLiteral(kPNGImageMime) || flavor.EqualsLiteral(kGIFImageMime)) { nsCOMPtr<nsIInputStream> stream; NS_NewCStringInputStream(getter_AddRefs(stream), item.data().get_nsCString()); 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); nsCString data = item.data().get_nsCString(); rv = dataWrapper->SetData(data); NS_ENSURE_SUCCESS(rv, rv);
--- a/widget/nsITransferable.idl +++ b/widget/nsITransferable.idl @@ -44,16 +44,18 @@ interface nsIDOMNode; #define kFilePromiseURLMime "application/x-moz-file-promise-url" // the destination filename for a file promise #define kFilePromiseDestFilename "application/x-moz-file-promise-dest-filename" // a dataless flavor used to interact with the OS during file drags #define kFilePromiseMime "application/x-moz-file-promise" // 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" + %} /** * nsIFlavorDataProvider allows a flavor to 'promise' data later, * supplying the data lazily. * * To use it, call setTransferData, passing the flavor string,
--- a/widget/nsPrimitiveHelpers.cpp +++ b/widget/nsPrimitiveHelpers.cpp @@ -43,17 +43,17 @@ void nsPrimitiveHelpers :: CreatePrimitiveForData ( const char* aFlavor, const void* aDataBuff, uint32_t aDataLen, nsISupports** aPrimitive ) { if ( !aPrimitive ) 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 ) { const char * start = reinterpret_cast<const char*>(aDataBuff); primitive->SetData(Substring(start, start + aDataLen)); NS_ADDREF(*aPrimitive = primitive); } } @@ -128,17 +128,17 @@ void nsPrimitiveHelpers :: CreateDataFromPrimitive ( const char* aFlavor, nsISupports* aPrimitive, void** aDataBuff, uint32_t aDataLen ) { if ( !aDataBuff ) return; *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; plainText->GetData ( data ); *aDataBuff = ToNewCString(data); } } else {
--- a/widget/windows/nsClipboard.cpp +++ b/widget/windows/nsClipboard.cpp @@ -37,16 +37,17 @@ #include "nsIObserverService.h" using mozilla::LogLevel; 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"); //------------------------------------------------------------------------- // // nsClipboard constructor // //------------------------------------------------------------------------- nsClipboard::nsClipboard() : nsBaseClipboard() @@ -103,16 +104,18 @@ UINT nsClipboard::GetFormat(const char* strcmp(aMimeStr, kPNGImageMime) == 0) format = CF_DIBV5; else if (strcmp(aMimeStr, kFileMime) == 0 || strcmp(aMimeStr, kFilePromiseMime) == 0) format = CF_HDROP; 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()); return format; } //------------------------------------------------------------------------- nsresult nsClipboard::CreateNativeDataObject(nsITransferable * aTransferable, IDataObject ** aDataObj, nsIURI * uri) @@ -529,16 +532,19 @@ nsresult nsClipboard::GetNativeDataOffCl uint32_t allocLen = 0; if ( NS_SUCCEEDED(GetGlobalData(stm.hGlobal, aData, &allocLen)) ) { if ( fe.cfFormat == CF_HTML ) { // CF_HTML is actually UTF8, not unicode, so disregard the assumption // above. We have to check the header for the actual length, and we'll // 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 // Reference: http://msdn.microsoft.com/en-us/library/bb776902(v=vs.85).aspx NS_ASSERTION(allocLen == sizeof(DWORD), "CFSTR_PREFERREDDROPEFFECT should return a DWORD"); *aLen = allocLen; } else { @@ -677,26 +683,29 @@ nsresult nsClipboard::GetDataFromDataObj else if ( strcmp(flavorStr, kJPEGImageMime) == 0 || strcmp(flavorStr, kJPGImageMime) == 0 || strcmp(flavorStr, kPNGImageMime) == 0) { nsIInputStream * imageStream = reinterpret_cast<nsIInputStream*>(data); genericDataWrapper = do_QueryInterface(imageStream); 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) ); free(data); } NS_ASSERTION ( genericDataWrapper, "About to put null data into the transferable" ); aTransferable->SetTransferData(flavorStr, genericDataWrapper, dataLen);
--- a/widget/windows/nsClipboard.h +++ b/widget/windows/nsClipboard.h @@ -55,16 +55,17 @@ public: // This function returns the internal Windows clipboard format identifier // for a given Mime string. The default is to map kHTMLMime ("text/html") // to the clipboard format CF_HTML ("HTLM Format"), but it can also be // registered as clipboard format "text/html" to support previous versions // of Gecko. 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; NS_IMETHOD GetNativeClipboardData ( nsITransferable * aTransferable, int32_t aWhichClipboard ) override; static bool IsInternetShortcut ( const nsAString& inFileName ) ; static bool FindURLFromLocalFile ( IDataObject* inDataObject, UINT inIndex, void** outData, uint32_t* outDataLen ) ; static bool FindURLFromNativeURL ( IDataObject* inDataObject, UINT inIndex, void** outData, uint32_t* outDataLen ) ;
--- a/widget/windows/nsDataObj.cpp +++ b/widget/windows/nsDataObj.cpp @@ -1323,17 +1323,17 @@ HRESULT nsDataObj::GetText(const nsACStr data = utf8HTML; allocLen = strlen(utf8HTML) + sizeof(char); } else { NS_WARNING ( "Oh no, couldn't convert to HTML" ); 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); } hGlobalMemory = (HGLOBAL)GlobalAlloc(GMEM_MOVEABLE, allocLen); // Copy text to Global Memory Area