Revert Bug 1951225 - for causing failures @test_clipboard_cache_chrome.html.
This reverts commitcfb55158a2. Revert "Bug 1951225 - Part 2-5: Implement new GetNativeClipboardData() on geckoview; r=geckoview-reviewers,m_kato" This reverts commit720b17e231. Revert "Bug 1951225 - Part 2-4: Implement new GetNativeClipboardData() on windows widget; r=win-reviewers,gstoll" This reverts commit5b37cd1b74. Revert "Bug 1951225 - Part 2-3: Implement new GetNativeClipboardData() on gtk widget; r=stransky" This reverts commited6a7ee1eb. Revert "Bug 1951225 - Part 2-2: Implement new GetNativeClipboardData() on headless widget; r=spohl" This reverts commitd05e31225f. Revert "Bug 1951225 - Part 2-1: Implement new GetNativeClipboardData() on cocoa widget; r=mac-reviewers,bradwerth" This reverts commite54df44d9b. Revert "Bug 1951225 - Part 1: Introduce new {Async}GetNativeClipboardData(); r=gstoll" This reverts commit516732b93f.
This commit is contained in:
committed by
agoloman@mozilla.com
parent
37f125f5e9
commit
c3d6835e06
@@ -108,49 +108,65 @@ nsClipboard::SetNativeClipboardData(nsITransferable* aTransferable,
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
mozilla::Result<nsCOMPtr<nsISupports>, nsresult>
|
||||
nsClipboard::GetNativeClipboardData(const nsACString& aFlavor,
|
||||
NS_IMETHODIMP
|
||||
nsClipboard::GetNativeClipboardData(nsITransferable* aTransferable,
|
||||
ClipboardType aWhichClipboard) {
|
||||
MOZ_DIAGNOSTIC_ASSERT(aTransferable);
|
||||
MOZ_DIAGNOSTIC_ASSERT(
|
||||
nsIClipboard::IsClipboardTypeSupported(aWhichClipboard));
|
||||
|
||||
if (!jni::IsAvailable()) {
|
||||
return Err(NS_ERROR_NOT_AVAILABLE);
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
if (aFlavor.EqualsLiteral(kTextMime) || aFlavor.EqualsLiteral(kHTMLMime)) {
|
||||
auto text = java::Clipboard::GetTextData(
|
||||
java::GeckoAppShell::GetApplicationContext(), aFlavor);
|
||||
if (!text) {
|
||||
return nsCOMPtr<nsISupports>{};
|
||||
nsTArray<nsCString> flavors;
|
||||
aTransferable->FlavorsTransferableCanImport(flavors);
|
||||
|
||||
for (auto& flavorStr : flavors) {
|
||||
if (flavorStr.EqualsLiteral(kTextMime) ||
|
||||
flavorStr.EqualsLiteral(kHTMLMime)) {
|
||||
auto text = java::Clipboard::GetTextData(
|
||||
java::GeckoAppShell::GetApplicationContext(), flavorStr);
|
||||
if (!text) {
|
||||
continue;
|
||||
}
|
||||
nsString buffer = text->ToString();
|
||||
if (buffer.IsEmpty()) {
|
||||
continue;
|
||||
}
|
||||
nsCOMPtr<nsISupports> wrapper;
|
||||
nsPrimitiveHelpers::CreatePrimitiveForData(flavorStr, buffer.get(),
|
||||
buffer.Length() * 2,
|
||||
getter_AddRefs(wrapper));
|
||||
if (wrapper) {
|
||||
aTransferable->SetTransferData(flavorStr.get(), wrapper);
|
||||
return NS_OK;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
nsString buffer = text->ToString();
|
||||
if (buffer.IsEmpty()) {
|
||||
return nsCOMPtr<nsISupports>{};
|
||||
|
||||
mozilla::jni::ByteArray::LocalRef bytes;
|
||||
nsresult rv = java::Clipboard::GetRawData(flavorStr, &bytes);
|
||||
if (NS_FAILED(rv) || !bytes) {
|
||||
continue;
|
||||
}
|
||||
nsCOMPtr<nsIInputStream> byteStream;
|
||||
rv = NS_NewByteInputStream(
|
||||
getter_AddRefs(byteStream),
|
||||
mozilla::Span(
|
||||
reinterpret_cast<const char*>(bytes->GetElements().Elements()),
|
||||
bytes->Length()),
|
||||
NS_ASSIGNMENT_COPY);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
continue;
|
||||
}
|
||||
rv = aTransferable->SetTransferData(flavorStr.get(), byteStream);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
continue;
|
||||
}
|
||||
nsCOMPtr<nsISupports> wrapper;
|
||||
nsPrimitiveHelpers::CreatePrimitiveForData(
|
||||
aFlavor, buffer.get(), buffer.Length() * 2, getter_AddRefs(wrapper));
|
||||
return std::move(wrapper);
|
||||
}
|
||||
|
||||
mozilla::jni::ByteArray::LocalRef bytes;
|
||||
nsresult rv = java::Clipboard::GetRawData(aFlavor, &bytes);
|
||||
if (NS_FAILED(rv) || !bytes) {
|
||||
return nsCOMPtr<nsISupports>{};
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIInputStream> byteStream;
|
||||
rv = NS_NewByteInputStream(getter_AddRefs(byteStream),
|
||||
mozilla::Span(reinterpret_cast<const char*>(
|
||||
bytes->GetElements().Elements()),
|
||||
bytes->Length()),
|
||||
NS_ASSIGNMENT_COPY);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return nsCOMPtr<nsISupports>{};
|
||||
}
|
||||
|
||||
return nsCOMPtr<nsISupports>(std::move(byteStream));
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult nsClipboard::EmptyNativeClipboardData(ClipboardType aWhichClipboard) {
|
||||
|
||||
@@ -27,9 +27,8 @@ class nsClipboard final : public nsBaseClipboard {
|
||||
// Implement the native clipboard behavior.
|
||||
NS_IMETHOD SetNativeClipboardData(nsITransferable* aTransferable,
|
||||
ClipboardType aWhichClipboard) override;
|
||||
virtual mozilla::Result<nsCOMPtr<nsISupports>, nsresult>
|
||||
GetNativeClipboardData(const nsACString& aFlavor,
|
||||
ClipboardType aWhichClipboard) override;
|
||||
NS_IMETHOD GetNativeClipboardData(nsITransferable* aTransferable,
|
||||
ClipboardType aWhichClipboard) override;
|
||||
nsresult EmptyNativeClipboardData(ClipboardType aWhichClipboard) override;
|
||||
mozilla::Result<bool, nsresult> HasNativeClipboardDataMatchingFlavors(
|
||||
const nsTArray<nsCString>& aFlavorList,
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
|
||||
class nsITransferable;
|
||||
|
||||
class nsClipboard final : public nsBaseClipboard {
|
||||
class nsClipboard : public nsBaseClipboard {
|
||||
public:
|
||||
nsClipboard();
|
||||
|
||||
@@ -33,14 +33,12 @@ class nsClipboard final : public nsBaseClipboard {
|
||||
static NSDictionary* PasteboardDictFromTransferable(
|
||||
nsITransferable* aTransferable);
|
||||
// aPasteboardType is being retained and needs to be released by the caller.
|
||||
static bool IsStringType(const nsACString& aMIMEType,
|
||||
static bool IsStringType(const nsCString& aMIMEType,
|
||||
NSString** aPasteboardType);
|
||||
static bool IsImageType(const nsACString& aMIMEType);
|
||||
static NSString* WrapHtmlForSystemPasteboard(NSString* aString);
|
||||
static nsresult TransferableFromPasteboard(nsITransferable* aTransferable,
|
||||
NSPasteboard* pboard);
|
||||
static mozilla::Result<nsCOMPtr<nsISupports>, nsresult> GetDataFromPasteboard(
|
||||
const nsACString& aFlavor, NSPasteboard* aPasteboard);
|
||||
mozilla::Result<int32_t, nsresult> GetNativeClipboardSequenceNumber(
|
||||
ClipboardType aWhichClipboard) override;
|
||||
|
||||
@@ -48,8 +46,8 @@ class nsClipboard final : public nsBaseClipboard {
|
||||
// Implement the native clipboard behavior.
|
||||
NS_IMETHOD SetNativeClipboardData(nsITransferable* aTransferable,
|
||||
ClipboardType aWhichClipboard) override;
|
||||
mozilla::Result<nsCOMPtr<nsISupports>, nsresult> GetNativeClipboardData(
|
||||
const nsACString& aFlavor, ClipboardType aWhichClipboard) override;
|
||||
NS_IMETHOD GetNativeClipboardData(nsITransferable* aTransferable,
|
||||
ClipboardType aWhichClipboard) override;
|
||||
nsresult EmptyNativeClipboardData(ClipboardType aWhichClipboard) override;
|
||||
mozilla::Result<bool, nsresult> HasNativeClipboardDataMatchingFlavors(
|
||||
const nsTArray<nsCString>& aFlavorList,
|
||||
|
||||
@@ -45,8 +45,8 @@ namespace {
|
||||
// We separate this into its own function because after an @try, all local
|
||||
// variables within that function get marked as volatile, and our C++ type
|
||||
// system doesn't like volatile things.
|
||||
static NSData* GetNSDataFromPasteboard(NSPasteboard* aPasteboard,
|
||||
NSString* aType) {
|
||||
static NSData* GetDataFromPasteboard(NSPasteboard* aPasteboard,
|
||||
NSString* aType) {
|
||||
NSData* data = nil;
|
||||
@try {
|
||||
data = [aPasteboard dataForType:aType];
|
||||
@@ -179,22 +179,177 @@ nsresult nsClipboard::TransferableFromPasteboard(
|
||||
// obtained through conversion)
|
||||
nsTArray<nsCString> flavors;
|
||||
nsresult rv = aTransferable->FlavorsTransferableCanImport(flavors);
|
||||
if (NS_FAILED(rv)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
if (NS_FAILED(rv)) return NS_ERROR_FAILURE;
|
||||
|
||||
for (uint32_t i = 0; i < flavors.Length(); i++) {
|
||||
nsCString& flavorStr = flavors[i];
|
||||
|
||||
auto dataOrError = GetDataFromPasteboard(flavorStr, cocoaPasteboard);
|
||||
if (dataOrError.isErr()) {
|
||||
continue;
|
||||
}
|
||||
// printf("looking for clipboard data of type %s\n", flavorStr.get());
|
||||
|
||||
if (auto data = dataOrError.inspect()) {
|
||||
aTransferable->SetTransferData(flavorStr.get(), data);
|
||||
// XXX Maybe try to fill in more types? Is there a point?
|
||||
NSString* pboardType = nil;
|
||||
if (nsClipboard::IsStringType(flavorStr, &pboardType)) {
|
||||
NSString* pString = [cocoaPasteboard stringForType:pboardType];
|
||||
if (!pString) {
|
||||
continue;
|
||||
}
|
||||
|
||||
NSData* stringData;
|
||||
bool isRTF = [pboardType
|
||||
isEqualToString:[UTIHelper stringFromPboardType:NSPasteboardTypeRTF]];
|
||||
if (isRTF) {
|
||||
stringData = [pString dataUsingEncoding:NSASCIIStringEncoding];
|
||||
} else {
|
||||
stringData = [pString dataUsingEncoding:NSUnicodeStringEncoding];
|
||||
}
|
||||
unsigned int dataLength = [stringData length];
|
||||
void* clipboardDataPtr = malloc(dataLength);
|
||||
if (!clipboardDataPtr) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
[stringData getBytes:clipboardDataPtr length:dataLength];
|
||||
|
||||
// The DOM only wants LF, so convert from MacOS line endings to DOM line
|
||||
// endings.
|
||||
int32_t signedDataLength = dataLength;
|
||||
nsLinebreakHelpers::ConvertPlatformToDOMLinebreaks(
|
||||
isRTF, &clipboardDataPtr, &signedDataLength);
|
||||
dataLength = signedDataLength;
|
||||
|
||||
// skip BOM (Byte Order Mark to distinguish little or big endian)
|
||||
char16_t* clipboardDataPtrNoBOM = (char16_t*)clipboardDataPtr;
|
||||
if ((dataLength > 2) && ((clipboardDataPtrNoBOM[0] == 0xFEFF) ||
|
||||
(clipboardDataPtrNoBOM[0] == 0xFFFE))) {
|
||||
dataLength -= sizeof(char16_t);
|
||||
clipboardDataPtrNoBOM += 1;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsISupports> genericDataWrapper;
|
||||
nsPrimitiveHelpers::CreatePrimitiveForData(
|
||||
flavorStr, clipboardDataPtrNoBOM, dataLength,
|
||||
getter_AddRefs(genericDataWrapper));
|
||||
aTransferable->SetTransferData(flavorStr.get(), genericDataWrapper);
|
||||
free(clipboardDataPtr);
|
||||
break;
|
||||
} else if (flavorStr.EqualsLiteral(kFileMime)) {
|
||||
NSArray* items = [cocoaPasteboard pasteboardItems];
|
||||
if (!items || [items count] <= 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// XXX we don't support multiple clipboard item on DOM and XPCOM interface
|
||||
// for now, so we only get the data from the first pasteboard item.
|
||||
NSPasteboardItem* item = [items objectAtIndex:0];
|
||||
if (!item) {
|
||||
continue;
|
||||
}
|
||||
|
||||
nsCocoaUtils::SetTransferDataForTypeFromPasteboardItem(aTransferable,
|
||||
flavorStr, item);
|
||||
} else if (flavorStr.EqualsLiteral(kCustomTypesMime)) {
|
||||
NSString* type = [cocoaPasteboard
|
||||
availableTypeFromArray:
|
||||
[NSArray
|
||||
arrayWithObject:[UTIHelper stringFromPboardType:
|
||||
kMozCustomTypesPboardType]]];
|
||||
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 length:dataLength];
|
||||
|
||||
nsCOMPtr<nsISupports> genericDataWrapper;
|
||||
nsPrimitiveHelpers::CreatePrimitiveForData(
|
||||
flavorStr, clipboardDataPtr, dataLength,
|
||||
getter_AddRefs(genericDataWrapper));
|
||||
|
||||
aTransferable->SetTransferData(flavorStr.get(), genericDataWrapper);
|
||||
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:
|
||||
[UTIHelper
|
||||
stringFromPboardType:(NSString*)kUTTypeFileURL],
|
||||
[UTIHelper stringFromPboardType:NSPasteboardTypeTIFF],
|
||||
[UTIHelper stringFromPboardType:NSPasteboardTypePNG],
|
||||
nil]];
|
||||
if (!type) continue;
|
||||
|
||||
// Read data off the clipboard
|
||||
NSData* pasteboardData = GetDataFromPasteboard(cocoaPasteboard, type);
|
||||
if (!pasteboardData) continue;
|
||||
|
||||
// Figure out what type we're converting to
|
||||
CFStringRef outputType = NULL;
|
||||
if (flavorStr.EqualsLiteral(kJPEGImageMime) ||
|
||||
flavorStr.EqualsLiteral(kJPGImageMime))
|
||||
outputType = CFSTR("public.jpeg");
|
||||
else if (flavorStr.EqualsLiteral(kPNGImageMime))
|
||||
outputType = CFSTR("public.png");
|
||||
else if (flavorStr.EqualsLiteral(kGIFImageMime))
|
||||
outputType = CFSTR("com.compuserve.gif");
|
||||
else
|
||||
continue;
|
||||
|
||||
// Use ImageIO to interpret the data on the clipboard and transcode.
|
||||
// Note that ImageIO, like all CF APIs, allows NULLs to propagate freely
|
||||
// and safely in most cases (like ObjC). A notable exception is CFRelease.
|
||||
NSDictionary* options = [NSDictionary
|
||||
dictionaryWithObjectsAndKeys:(NSNumber*)kCFBooleanTrue,
|
||||
kCGImageSourceShouldAllowFloat, type,
|
||||
kCGImageSourceTypeIdentifierHint, nil];
|
||||
CGImageSourceRef source = nullptr;
|
||||
if (type == [UTIHelper stringFromPboardType:(NSString*)kUTTypeFileURL]) {
|
||||
NSString* urlStr = [cocoaPasteboard stringForType:type];
|
||||
NSURL* url = [NSURL URLWithString:urlStr];
|
||||
source =
|
||||
CGImageSourceCreateWithURL((CFURLRef)url, (CFDictionaryRef)options);
|
||||
} else {
|
||||
source = CGImageSourceCreateWithData((CFDataRef)pasteboardData,
|
||||
(CFDictionaryRef)options);
|
||||
}
|
||||
|
||||
NSMutableData* encodedData = [NSMutableData data];
|
||||
CGImageDestinationRef dest = CGImageDestinationCreateWithData(
|
||||
(CFMutableDataRef)encodedData, outputType, 1, NULL);
|
||||
CGImageDestinationAddImageFromSource(dest, source, 0, NULL);
|
||||
bool successfullyConverted = CGImageDestinationFinalize(dest);
|
||||
|
||||
if (successfullyConverted) {
|
||||
// Put the converted data in a form Gecko can understand
|
||||
nsCOMPtr<nsIInputStream> byteStream;
|
||||
NS_NewByteInputStream(getter_AddRefs(byteStream),
|
||||
mozilla::Span((const char*)[encodedData bytes],
|
||||
[encodedData length]),
|
||||
NS_ASSIGNMENT_COPY);
|
||||
|
||||
aTransferable->SetTransferData(flavorStr.get(), byteStream);
|
||||
}
|
||||
|
||||
if (dest) CFRelease(dest);
|
||||
if (source) CFRelease(source);
|
||||
|
||||
if (successfullyConverted) {
|
||||
// XXX Maybe try to fill in more types? Is there a point?
|
||||
break;
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -203,221 +358,51 @@ nsresult nsClipboard::TransferableFromPasteboard(
|
||||
NS_OBJC_END_TRY_BLOCK_RETURN(NS_ERROR_FAILURE);
|
||||
}
|
||||
|
||||
mozilla::Result<nsCOMPtr<nsISupports>, nsresult>
|
||||
nsClipboard::GetDataFromPasteboard(const nsACString& aFlavor,
|
||||
NSPasteboard* aPasteboard) {
|
||||
NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
|
||||
|
||||
NSString* pboardType = nil;
|
||||
if (nsClipboard::IsStringType(aFlavor, &pboardType)) {
|
||||
NSString* pString = [aPasteboard stringForType:pboardType];
|
||||
if (!pString) {
|
||||
return nsCOMPtr<nsISupports>{};
|
||||
}
|
||||
|
||||
NSData* stringData;
|
||||
bool isRTF = [pboardType
|
||||
isEqualToString:[UTIHelper stringFromPboardType:NSPasteboardTypeRTF]];
|
||||
if (isRTF) {
|
||||
stringData = [pString dataUsingEncoding:NSASCIIStringEncoding];
|
||||
} else {
|
||||
stringData = [pString dataUsingEncoding:NSUnicodeStringEncoding];
|
||||
}
|
||||
unsigned int dataLength = [stringData length];
|
||||
void* clipboardDataPtr = malloc(dataLength);
|
||||
if (!clipboardDataPtr) {
|
||||
return mozilla::Err(NS_ERROR_OUT_OF_MEMORY);
|
||||
}
|
||||
[stringData getBytes:clipboardDataPtr length:dataLength];
|
||||
|
||||
// The DOM only wants LF, so convert from MacOS line endings to DOM line
|
||||
// endings.
|
||||
int32_t signedDataLength = dataLength;
|
||||
nsLinebreakHelpers::ConvertPlatformToDOMLinebreaks(isRTF, &clipboardDataPtr,
|
||||
&signedDataLength);
|
||||
dataLength = signedDataLength;
|
||||
|
||||
// skip BOM (Byte Order Mark to distinguish little or big endian)
|
||||
char16_t* clipboardDataPtrNoBOM = (char16_t*)clipboardDataPtr;
|
||||
if ((dataLength > 2) && ((clipboardDataPtrNoBOM[0] == 0xFEFF) ||
|
||||
(clipboardDataPtrNoBOM[0] == 0xFFFE))) {
|
||||
dataLength -= sizeof(char16_t);
|
||||
clipboardDataPtrNoBOM += 1;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsISupports> genericDataWrapper;
|
||||
nsPrimitiveHelpers::CreatePrimitiveForData(
|
||||
aFlavor, clipboardDataPtrNoBOM, dataLength,
|
||||
getter_AddRefs(genericDataWrapper));
|
||||
free(clipboardDataPtr);
|
||||
return std::move(genericDataWrapper);
|
||||
}
|
||||
|
||||
if (aFlavor.EqualsLiteral(kFileMime)) {
|
||||
NSArray* items = [aPasteboard pasteboardItems];
|
||||
if (!items || [items count] <= 0) {
|
||||
return nsCOMPtr<nsISupports>{};
|
||||
}
|
||||
|
||||
// XXX we don't support multiple clipboard item on DOM and XPCOM interface
|
||||
// for now, so we only get the data from the first pasteboard item.
|
||||
NSPasteboardItem* item = [items objectAtIndex:0];
|
||||
if (!item) {
|
||||
return nsCOMPtr<nsISupports>{};
|
||||
}
|
||||
|
||||
return nsCOMPtr<nsISupports>(
|
||||
nsCocoaUtils::GetDataFromPasteboardItem(aFlavor, item));
|
||||
}
|
||||
|
||||
if (aFlavor.EqualsLiteral(kCustomTypesMime)) {
|
||||
NSString* type = [aPasteboard
|
||||
availableTypeFromArray:
|
||||
[NSArray
|
||||
arrayWithObject:[UTIHelper stringFromPboardType:
|
||||
kMozCustomTypesPboardType]]];
|
||||
if (!type) {
|
||||
return nsCOMPtr<nsISupports>{};
|
||||
}
|
||||
|
||||
NSData* pasteboardData = GetNSDataFromPasteboard(aPasteboard, type);
|
||||
if (!pasteboardData) {
|
||||
return nsCOMPtr<nsISupports>{};
|
||||
}
|
||||
|
||||
unsigned int dataLength = [pasteboardData length];
|
||||
void* clipboardDataPtr = malloc(dataLength);
|
||||
if (!clipboardDataPtr) {
|
||||
return mozilla::Err(NS_ERROR_OUT_OF_MEMORY);
|
||||
}
|
||||
[pasteboardData getBytes:clipboardDataPtr length:dataLength];
|
||||
|
||||
nsCOMPtr<nsISupports> genericDataWrapper;
|
||||
nsPrimitiveHelpers::CreatePrimitiveForData(
|
||||
aFlavor, clipboardDataPtr, dataLength,
|
||||
getter_AddRefs(genericDataWrapper));
|
||||
free(clipboardDataPtr);
|
||||
return std::move(genericDataWrapper);
|
||||
}
|
||||
|
||||
if (aFlavor.EqualsLiteral(kJPEGImageMime) ||
|
||||
aFlavor.EqualsLiteral(kJPGImageMime) ||
|
||||
aFlavor.EqualsLiteral(kPNGImageMime) ||
|
||||
aFlavor.EqualsLiteral(kGIFImageMime)) {
|
||||
// Figure out if there's data on the pasteboard we can grab (sanity check)
|
||||
NSString* type = [aPasteboard
|
||||
availableTypeFromArray:
|
||||
[NSArray
|
||||
arrayWithObjects:[UTIHelper
|
||||
stringFromPboardType:(NSString*)
|
||||
kUTTypeFileURL],
|
||||
[UTIHelper
|
||||
stringFromPboardType:NSPasteboardTypeTIFF],
|
||||
[UTIHelper
|
||||
stringFromPboardType:NSPasteboardTypePNG],
|
||||
nil]];
|
||||
if (!type) {
|
||||
return nsCOMPtr<nsISupports>{};
|
||||
}
|
||||
|
||||
// Read data off the clipboard
|
||||
NSData* pasteboardData = GetNSDataFromPasteboard(aPasteboard, type);
|
||||
if (!pasteboardData) {
|
||||
return nsCOMPtr<nsISupports>{};
|
||||
}
|
||||
|
||||
// Figure out what type we're converting to
|
||||
CFStringRef outputType = NULL;
|
||||
if (aFlavor.EqualsLiteral(kJPEGImageMime) ||
|
||||
aFlavor.EqualsLiteral(kJPGImageMime)) {
|
||||
outputType = CFSTR("public.jpeg");
|
||||
} else if (aFlavor.EqualsLiteral(kPNGImageMime)) {
|
||||
outputType = CFSTR("public.png");
|
||||
} else if (aFlavor.EqualsLiteral(kGIFImageMime)) {
|
||||
outputType = CFSTR("com.compuserve.gif");
|
||||
} else {
|
||||
return nsCOMPtr<nsISupports>{};
|
||||
}
|
||||
|
||||
// Use ImageIO to interpret the data on the clipboard and transcode.
|
||||
// Note that ImageIO, like all CF APIs, allows NULLs to propagate freely
|
||||
// and safely in most cases (like ObjC). A notable exception is CFRelease.
|
||||
NSDictionary* options = [NSDictionary
|
||||
dictionaryWithObjectsAndKeys:(NSNumber*)kCFBooleanTrue,
|
||||
kCGImageSourceShouldAllowFloat, type,
|
||||
kCGImageSourceTypeIdentifierHint, nil];
|
||||
CGImageSourceRef source = nullptr;
|
||||
if (type == [UTIHelper stringFromPboardType:(NSString*)kUTTypeFileURL]) {
|
||||
NSString* urlStr = [aPasteboard stringForType:type];
|
||||
NSURL* url = [NSURL URLWithString:urlStr];
|
||||
source =
|
||||
CGImageSourceCreateWithURL((CFURLRef)url, (CFDictionaryRef)options);
|
||||
} else {
|
||||
source = CGImageSourceCreateWithData((CFDataRef)pasteboardData,
|
||||
(CFDictionaryRef)options);
|
||||
}
|
||||
|
||||
NSMutableData* encodedData = [NSMutableData data];
|
||||
CGImageDestinationRef dest = CGImageDestinationCreateWithData(
|
||||
(CFMutableDataRef)encodedData, outputType, 1, NULL);
|
||||
CGImageDestinationAddImageFromSource(dest, source, 0, NULL);
|
||||
|
||||
nsCOMPtr<nsIInputStream> byteStream;
|
||||
if (CGImageDestinationFinalize(dest)) {
|
||||
// Put the converted data in a form Gecko can understand
|
||||
NS_NewByteInputStream(
|
||||
getter_AddRefs(byteStream),
|
||||
mozilla::Span((const char*)[encodedData bytes], [encodedData length]),
|
||||
NS_ASSIGNMENT_COPY);
|
||||
}
|
||||
|
||||
if (dest) {
|
||||
CFRelease(dest);
|
||||
}
|
||||
if (source) {
|
||||
CFRelease(source);
|
||||
}
|
||||
|
||||
return nsCOMPtr<nsISupports>(std::move(byteStream));
|
||||
}
|
||||
|
||||
return nsCOMPtr<nsISupports>{};
|
||||
|
||||
NS_OBJC_END_TRY_BLOCK_RETURN(mozilla::Err(NS_ERROR_FAILURE));
|
||||
}
|
||||
|
||||
mozilla::Result<nsCOMPtr<nsISupports>, nsresult>
|
||||
nsClipboard::GetNativeClipboardData(const nsACString& aFlavor,
|
||||
NS_IMETHODIMP
|
||||
nsClipboard::GetNativeClipboardData(nsITransferable* aTransferable,
|
||||
ClipboardType aWhichClipboard) {
|
||||
NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
|
||||
|
||||
MOZ_DIAGNOSTIC_ASSERT(aTransferable);
|
||||
MOZ_DIAGNOSTIC_ASSERT(
|
||||
nsIClipboard::IsClipboardTypeSupported(aWhichClipboard));
|
||||
|
||||
if (kSelectionCache == aWhichClipboard) {
|
||||
if (!sSelectionCache) {
|
||||
return nsCOMPtr<nsISupports>{};
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsISupports> dataSupports;
|
||||
if (NS_FAILED(sSelectionCache->GetTransferData(
|
||||
PromiseFlatCString(aFlavor).get(), getter_AddRefs(dataSupports)))) {
|
||||
return nsCOMPtr<nsISupports>{};
|
||||
// get flavor list that includes all acceptable flavors (including ones
|
||||
// obtained through conversion)
|
||||
nsTArray<nsCString> flavors;
|
||||
nsresult rv = aTransferable->FlavorsTransferableCanImport(flavors);
|
||||
if (NS_FAILED(rv)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
MOZ_CLIPBOARD_LOG("%s: getting %s from cache.", __FUNCTION__,
|
||||
PromiseFlatCString(aFlavor).get());
|
||||
return std::move(dataSupports);
|
||||
for (const auto& flavor : flavors) {
|
||||
nsCOMPtr<nsISupports> dataSupports;
|
||||
rv = sSelectionCache->GetTransferData(flavor.get(),
|
||||
getter_AddRefs(dataSupports));
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
MOZ_CLIPBOARD_LOG("%s: getting %s from cache.", __FUNCTION__,
|
||||
flavor.get());
|
||||
aTransferable->SetTransferData(flavor.get(), dataSupports);
|
||||
// XXX Maybe try to fill in more types? Is there a point?
|
||||
break;
|
||||
}
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NSPasteboard* cocoaPasteboard = GetPasteboard(aWhichClipboard);
|
||||
if (!cocoaPasteboard) {
|
||||
return mozilla::Err(NS_ERROR_FAILURE);
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
return GetDataFromPasteboard(aFlavor, cocoaPasteboard);
|
||||
return TransferableFromPasteboard(aTransferable, cocoaPasteboard);
|
||||
|
||||
NS_OBJC_END_TRY_BLOCK_RETURN(mozilla::Err(NS_ERROR_FAILURE));
|
||||
NS_OBJC_END_TRY_BLOCK_RETURN(NS_ERROR_FAILURE);
|
||||
}
|
||||
|
||||
// returns true if we have *any* of the passed in flavors available for pasting
|
||||
@@ -513,7 +498,7 @@ nsClipboard::HasNativeClipboardDataMatchingFlavors(
|
||||
NSArray* items = [cocoaPasteboard pasteboardItems];
|
||||
if (items && [items count] > 0) {
|
||||
// XXX we only check the first pasteboard item as we only get data from
|
||||
// first item in GetDataFromPasteboard for now.
|
||||
// first item in TransferableFromPasteboard for now.
|
||||
if (NSPasteboardItem* item = [items objectAtIndex:0]) {
|
||||
if ([item availableTypeFromArray:
|
||||
[NSArray
|
||||
@@ -808,7 +793,7 @@ NSDictionary* nsClipboard::PasteboardDictFromTransferable(
|
||||
NS_OBJC_END_TRY_BLOCK_RETURN(nil);
|
||||
}
|
||||
|
||||
bool nsClipboard::IsStringType(const nsACString& aMIMEType,
|
||||
bool nsClipboard::IsStringType(const nsCString& aMIMEType,
|
||||
NSString** aPboardType) {
|
||||
if (aMIMEType.EqualsLiteral(kTextMime)) {
|
||||
*aPboardType = [UTIHelper stringFromPboardType:NSPasteboardTypeString];
|
||||
|
||||
@@ -509,12 +509,6 @@ class nsCocoaUtils {
|
||||
static bool IsValidPasteboardType(NSString* aAvailableType,
|
||||
bool aAllowFileURL);
|
||||
|
||||
/**
|
||||
* Get data for specific type from NSPasteboardItem.
|
||||
*/
|
||||
static already_AddRefed<nsISupports> GetDataFromPasteboardItem(
|
||||
const nsACString& aFlavor, NSPasteboardItem* aItem);
|
||||
|
||||
/**
|
||||
* Set data for specific type from NSPasteboardItem to Transferable.
|
||||
*/
|
||||
|
||||
@@ -1697,23 +1697,25 @@ NSString* nsCocoaUtils::GetTitleForURLFromPasteboardItem(
|
||||
NS_OBJC_END_TRY_BLOCK_RETURN(nil);
|
||||
}
|
||||
|
||||
already_AddRefed<nsISupports> nsCocoaUtils::GetDataFromPasteboardItem(
|
||||
const nsACString& aFlavor, NSPasteboardItem* aItem) {
|
||||
NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
|
||||
void nsCocoaUtils::SetTransferDataForTypeFromPasteboardItem(
|
||||
nsITransferable* aTransferable, const nsCString& aFlavor,
|
||||
NSPasteboardItem* aItem) {
|
||||
NS_OBJC_BEGIN_TRY_IGNORE_BLOCK;
|
||||
|
||||
if (!aItem) {
|
||||
return nullptr;
|
||||
if (!aTransferable || !aItem) {
|
||||
return;
|
||||
}
|
||||
|
||||
MOZ_LOG(gCocoaUtilsLog, LogLevel::Info,
|
||||
("nsCocoaUtils::GetDataFromPasteboardItem: looking for pasteboard "
|
||||
"data of type %s\n",
|
||||
PromiseFlatCString(aFlavor).get()));
|
||||
("nsCocoaUtils::SetTransferDataForTypeFromPasteboardItem: looking "
|
||||
"for pasteboard data of "
|
||||
"type %s\n",
|
||||
aFlavor.get()));
|
||||
|
||||
if (aFlavor.EqualsLiteral(kFileMime)) {
|
||||
NSString* filePath = nsCocoaUtils::GetFilePathFromPasteboardItem(aItem);
|
||||
if (!filePath) {
|
||||
return nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
unsigned int stringLength = [filePath length];
|
||||
@@ -1721,7 +1723,7 @@ already_AddRefed<nsISupports> nsCocoaUtils::GetDataFromPasteboardItem(
|
||||
(stringLength + 1) * sizeof(char16_t); // in bytes
|
||||
char16_t* clipboardDataPtr = (char16_t*)malloc(dataLength);
|
||||
if (!clipboardDataPtr) {
|
||||
return nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
[filePath getCharacters:reinterpret_cast<unichar*>(clipboardDataPtr)];
|
||||
@@ -1732,10 +1734,11 @@ already_AddRefed<nsISupports> nsCocoaUtils::GetDataFromPasteboardItem(
|
||||
getter_AddRefs(file));
|
||||
free(clipboardDataPtr);
|
||||
if (NS_FAILED(rv)) {
|
||||
return nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
return file.forget();
|
||||
aTransferable->SetTransferData(aFlavor.get(), file);
|
||||
return;
|
||||
}
|
||||
|
||||
if (aFlavor.EqualsLiteral(kCustomTypesMime)) {
|
||||
@@ -1744,17 +1747,17 @@ already_AddRefed<nsISupports> nsCocoaUtils::GetDataFromPasteboardItem(
|
||||
arrayWithObject:kMozCustomTypesPboardType]];
|
||||
if (!availableType ||
|
||||
!nsCocoaUtils::IsValidPasteboardType(availableType, false)) {
|
||||
return nullptr;
|
||||
return;
|
||||
}
|
||||
NSData* pasteboardData = [aItem dataForType:availableType];
|
||||
if (!pasteboardData) {
|
||||
return nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
unsigned int dataLength = [pasteboardData length];
|
||||
void* clipboardDataPtr = malloc(dataLength);
|
||||
if (!clipboardDataPtr) {
|
||||
return nullptr;
|
||||
return;
|
||||
}
|
||||
[pasteboardData getBytes:clipboardDataPtr length:dataLength];
|
||||
|
||||
@@ -1763,8 +1766,9 @@ already_AddRefed<nsISupports> nsCocoaUtils::GetDataFromPasteboardItem(
|
||||
aFlavor, clipboardDataPtr, dataLength,
|
||||
getter_AddRefs(genericDataWrapper));
|
||||
|
||||
aTransferable->SetTransferData(aFlavor.get(), genericDataWrapper);
|
||||
free(clipboardDataPtr);
|
||||
return genericDataWrapper.forget();
|
||||
return;
|
||||
}
|
||||
|
||||
NSString* pString = nil;
|
||||
@@ -1804,7 +1808,7 @@ already_AddRefed<nsISupports> nsCocoaUtils::GetDataFromPasteboardItem(
|
||||
unsigned int dataLength = [stringData length];
|
||||
void* clipboardDataPtr = malloc(dataLength);
|
||||
if (!clipboardDataPtr) {
|
||||
return nullptr;
|
||||
return;
|
||||
}
|
||||
[stringData getBytes:clipboardDataPtr length:dataLength];
|
||||
|
||||
@@ -1827,8 +1831,9 @@ already_AddRefed<nsISupports> nsCocoaUtils::GetDataFromPasteboardItem(
|
||||
nsPrimitiveHelpers::CreatePrimitiveForData(
|
||||
aFlavor, clipboardDataPtrNoBOM, dataLength,
|
||||
getter_AddRefs(genericDataWrapper));
|
||||
aTransferable->SetTransferData(aFlavor.get(), genericDataWrapper);
|
||||
free(clipboardDataPtr);
|
||||
return genericDataWrapper.forget();
|
||||
return;
|
||||
}
|
||||
|
||||
// We have never supported this on Mac OS X, we should someday. Normally
|
||||
@@ -1842,28 +1847,5 @@ already_AddRefed<nsISupports> nsCocoaUtils::GetDataFromPasteboardItem(
|
||||
}
|
||||
*/
|
||||
|
||||
return nullptr;
|
||||
|
||||
NS_OBJC_END_TRY_BLOCK_RETURN(nullptr);
|
||||
}
|
||||
|
||||
void nsCocoaUtils::SetTransferDataForTypeFromPasteboardItem(
|
||||
nsITransferable* aTransferable, const nsCString& aFlavor,
|
||||
NSPasteboardItem* aItem) {
|
||||
NS_OBJC_BEGIN_TRY_IGNORE_BLOCK;
|
||||
|
||||
if (!aTransferable || !aItem) {
|
||||
return;
|
||||
}
|
||||
|
||||
MOZ_LOG(gCocoaUtilsLog, LogLevel::Info,
|
||||
("nsCocoaUtils::SetTransferDataForTypeFromPasteboardItem: looking "
|
||||
"for pasteboard data of type %s\n",
|
||||
aFlavor.get()));
|
||||
|
||||
if (nsCOMPtr<nsISupports> data = GetDataFromPasteboardItem(aFlavor, aItem)) {
|
||||
aTransferable->SetTransferData(aFlavor.get(), data);
|
||||
}
|
||||
|
||||
NS_OBJC_END_TRY_IGNORE_BLOCK;
|
||||
}
|
||||
|
||||
@@ -84,6 +84,18 @@ static void clipboard_owner_change_cb(GtkClipboard* aGtkClipboard,
|
||||
|
||||
static bool GetHTMLCharset(Span<const char> aData, nsCString& str);
|
||||
|
||||
static void SetTransferableData(nsITransferable* aTransferable,
|
||||
const nsACString& aFlavor,
|
||||
const char* aClipboardData,
|
||||
uint32_t aClipboardDataLength) {
|
||||
MOZ_CLIPBOARD_LOG("SetTransferableData MIME %s\n",
|
||||
PromiseFlatCString(aFlavor).get());
|
||||
nsCOMPtr<nsISupports> wrapper;
|
||||
nsPrimitiveHelpers::CreatePrimitiveForData(
|
||||
aFlavor, aClipboardData, aClipboardDataLength, getter_AddRefs(wrapper));
|
||||
aTransferable->SetTransferData(PromiseFlatCString(aFlavor).get(), wrapper);
|
||||
}
|
||||
|
||||
ClipboardTargets ClipboardTargets::Clone() {
|
||||
ClipboardTargets ret;
|
||||
ret.mCount = mCount;
|
||||
@@ -368,17 +380,27 @@ nsClipboard::GetNativeClipboardSequenceNumber(ClipboardType aWhichClipboard) {
|
||||
: mGlobalSequenceNumber;
|
||||
}
|
||||
|
||||
static bool IsMIMEAtFlavourList(const nsTArray<nsCString>& aFlavourList,
|
||||
const char* aMime) {
|
||||
for (const auto& flavorStr : aFlavourList) {
|
||||
if (flavorStr.Equals(aMime)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// When clipboard contains only images, X11/Gtk tries to convert them
|
||||
// to text when we request text instead of just fail to provide the data.
|
||||
// So if clipboard contains images only remove text MIME offer.
|
||||
bool nsClipboard::HasSuitableData(int32_t aWhichClipboard,
|
||||
const nsACString& aFlavor) {
|
||||
MOZ_CLIPBOARD_LOG("nsClipboard::HasSuitableData");
|
||||
bool nsClipboard::FilterImportedFlavors(int32_t aWhichClipboard,
|
||||
nsTArray<nsCString>& aFlavors) {
|
||||
MOZ_CLIPBOARD_LOG("nsClipboard::FilterImportedFlavors");
|
||||
|
||||
auto targets = mContext->GetTargets(aWhichClipboard);
|
||||
if (!targets) {
|
||||
MOZ_CLIPBOARD_LOG(" X11: no targes at clipboard (null), quit.\n");
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
for (const auto& atom : targets.AsSpan()) {
|
||||
@@ -408,34 +430,68 @@ bool nsClipboard::HasSuitableData(int32_t aWhichClipboard,
|
||||
}
|
||||
|
||||
// So make sure we offer only types we have at clipboard.
|
||||
nsTArray<nsCString> clipboardFlavors;
|
||||
for (const auto& atom : targets.AsSpan()) {
|
||||
GUniquePtr<gchar> atom_name(gdk_atom_name(atom));
|
||||
if (!atom_name) {
|
||||
continue;
|
||||
}
|
||||
if (aFlavor.Equals(atom_name.get())) {
|
||||
return true;
|
||||
if (IsMIMEAtFlavourList(aFlavors, atom_name.get())) {
|
||||
clipboardFlavors.AppendElement(nsCString(atom_name.get()));
|
||||
}
|
||||
}
|
||||
|
||||
MOZ_CLIPBOARD_LOG(" X11: no suitable data in clipboard, quit.\n");
|
||||
return false;
|
||||
aFlavors.SwapElements(clipboardFlavors);
|
||||
#ifdef MOZ_LOGGING
|
||||
MOZ_CLIPBOARD_LOG(" X11: Flavors which match clipboard content:\n");
|
||||
for (uint32_t i = 0; i < aFlavors.Length(); i++) {
|
||||
MOZ_CLIPBOARD_LOG(" %s\n", aFlavors[i].get());
|
||||
}
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
static already_AddRefed<nsIFile> GetFileData(const nsACString& aURIList) {
|
||||
nsCOMPtr<nsIFile> file;
|
||||
static nsresult GetTransferableFlavors(nsITransferable* aTransferable,
|
||||
nsTArray<nsCString>& aFlavors) {
|
||||
if (!aTransferable) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
// Get a list of flavors this transferable can import
|
||||
nsresult rv = aTransferable->FlavorsTransferableCanImport(aFlavors);
|
||||
if (NS_FAILED(rv)) {
|
||||
MOZ_CLIPBOARD_LOG(" FlavorsTransferableCanImport falied!\n");
|
||||
return rv;
|
||||
}
|
||||
#ifdef MOZ_LOGGING
|
||||
MOZ_CLIPBOARD_LOG(" Flavors which can be imported:");
|
||||
for (const auto& flavor : aFlavors) {
|
||||
MOZ_CLIPBOARD_LOG(" %s", flavor.get());
|
||||
}
|
||||
#endif
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
static bool TransferableSetFile(nsITransferable* aTransferable,
|
||||
const nsACString& aURIList) {
|
||||
nsresult rv;
|
||||
nsTArray<nsCString> uris = mozilla::widget::ParseTextURIList(aURIList);
|
||||
if (!uris.IsEmpty()) {
|
||||
nsCOMPtr<nsIURI> fileURI;
|
||||
NS_NewURI(getter_AddRefs(fileURI), uris[0]);
|
||||
if (nsCOMPtr<nsIFileURL> fileURL = do_QueryInterface(fileURI)) {
|
||||
fileURL->GetFile(getter_AddRefs(file));
|
||||
if (nsCOMPtr<nsIFileURL> fileURL = do_QueryInterface(fileURI, &rv)) {
|
||||
nsCOMPtr<nsIFile> file;
|
||||
rv = fileURL->GetFile(getter_AddRefs(file));
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
aTransferable->SetTransferData(kFileMime, file);
|
||||
MOZ_CLIPBOARD_LOG(" successfully set file to clipboard\n");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return file.forget();
|
||||
return false;
|
||||
}
|
||||
|
||||
static already_AddRefed<nsISupports> GetHTMLData(Span<const char> aData) {
|
||||
static bool TransferableSetHTML(nsITransferable* aTransferable,
|
||||
Span<const char> aData) {
|
||||
nsLiteralCString mimeType(kHTMLMime);
|
||||
|
||||
// Convert text/html into our text format
|
||||
@@ -447,14 +503,16 @@ static already_AddRefed<nsISupports> GetHTMLData(Span<const char> aData) {
|
||||
charset.AssignLiteral("utf-8");
|
||||
}
|
||||
|
||||
MOZ_CLIPBOARD_LOG("GetHTMLData: HTML detected charset %s", charset.get());
|
||||
MOZ_CLIPBOARD_LOG("TransferableSetHTML: HTML detected charset %s",
|
||||
charset.get());
|
||||
// app which use "text/html" to copy&paste
|
||||
// get the decoder
|
||||
auto encoding = Encoding::ForLabelNoReplacement(charset);
|
||||
if (!encoding) {
|
||||
MOZ_CLIPBOARD_LOG("GetHTMLData: get unicode decoder error (charset: %s)",
|
||||
charset.get());
|
||||
return nullptr;
|
||||
MOZ_CLIPBOARD_LOG(
|
||||
"TransferableSetHTML: get unicode decoder error (charset: %s)",
|
||||
charset.get());
|
||||
return false;
|
||||
}
|
||||
|
||||
// According to spec html UTF-16BE/LE should be switched to UTF-8
|
||||
@@ -477,142 +535,151 @@ static already_AddRefed<nsISupports> GetHTMLData(Span<const char> aData) {
|
||||
if (enc != UTF_8_ENCODING && MOZ_CLIPBOARD_LOG_ENABLED()) {
|
||||
nsCString decoderName;
|
||||
enc->Name(decoderName);
|
||||
MOZ_CLIPBOARD_LOG("GetHTMLData: expected UTF-8 decoder but got %s",
|
||||
MOZ_CLIPBOARD_LOG("TransferableSetHTML: expected UTF-8 decoder but got %s",
|
||||
decoderName.get());
|
||||
}
|
||||
#endif
|
||||
if (NS_FAILED(rv)) {
|
||||
MOZ_CLIPBOARD_LOG("GetHTMLData: failed to decode HTML");
|
||||
return nullptr;
|
||||
MOZ_CLIPBOARD_LOG("TransferableSetHTML: failed to decode HTML");
|
||||
return false;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsISupports> wrapper;
|
||||
nsPrimitiveHelpers::CreatePrimitiveForData(
|
||||
mimeType, (const char*)unicodeData.BeginReading(),
|
||||
unicodeData.Length() * sizeof(char16_t), getter_AddRefs(wrapper));
|
||||
return wrapper.forget();
|
||||
SetTransferableData(aTransferable, mimeType,
|
||||
(const char*)unicodeData.BeginReading(),
|
||||
unicodeData.Length() * sizeof(char16_t));
|
||||
return true;
|
||||
}
|
||||
|
||||
mozilla::Result<nsCOMPtr<nsISupports>, nsresult>
|
||||
nsClipboard::GetNativeClipboardData(const nsACString& aFlavor,
|
||||
NS_IMETHODIMP
|
||||
nsClipboard::GetNativeClipboardData(nsITransferable* aTransferable,
|
||||
ClipboardType aWhichClipboard) {
|
||||
MOZ_DIAGNOSTIC_ASSERT(aTransferable);
|
||||
MOZ_DIAGNOSTIC_ASSERT(
|
||||
nsIClipboard::IsClipboardTypeSupported(aWhichClipboard));
|
||||
|
||||
MOZ_CLIPBOARD_LOG(
|
||||
"nsClipboard::GetNativeClipboardData (%s) for %s\n",
|
||||
aWhichClipboard == kSelectionClipboard ? "primary" : "clipboard",
|
||||
PromiseFlatCString(aFlavor).get());
|
||||
"nsClipboard::GetNativeClipboardData (%s)\n",
|
||||
aWhichClipboard == kSelectionClipboard ? "primary" : "clipboard");
|
||||
|
||||
// TODO: Ensure we don't re-enter here.
|
||||
if (!mContext) {
|
||||
return Err(NS_ERROR_FAILURE);
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
nsTArray<nsCString> flavors;
|
||||
nsresult rv = GetTransferableFlavors(aTransferable, flavors);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// Filter out MIME types on X11 to prevent unwanted conversions,
|
||||
// see Bug 1611407
|
||||
if (widget::GdkIsX11Display() && !HasSuitableData(aWhichClipboard, aFlavor)) {
|
||||
if (widget::GdkIsX11Display() &&
|
||||
!FilterImportedFlavors(aWhichClipboard, flavors)) {
|
||||
MOZ_CLIPBOARD_LOG(" Missing suitable clipboard data, quit.");
|
||||
return nsCOMPtr<nsISupports>{};
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (aFlavor.EqualsLiteral(kJPEGImageMime) ||
|
||||
aFlavor.EqualsLiteral(kJPGImageMime) ||
|
||||
aFlavor.EqualsLiteral(kPNGImageMime) ||
|
||||
aFlavor.EqualsLiteral(kGIFImageMime)) {
|
||||
// Emulate support for image/jpg
|
||||
nsAutoCString flavor(aFlavor.EqualsLiteral(kJPGImageMime)
|
||||
? kJPEGImageMime
|
||||
: PromiseFlatCString(aFlavor).get());
|
||||
MOZ_CLIPBOARD_LOG(" Getting image %s MIME clipboard data\n",
|
||||
flavor.get());
|
||||
for (uint32_t i = 0; i < flavors.Length(); i++) {
|
||||
nsCString& flavorStr = flavors[i];
|
||||
|
||||
if (flavorStr.EqualsLiteral(kJPEGImageMime) ||
|
||||
flavorStr.EqualsLiteral(kJPGImageMime) ||
|
||||
flavorStr.EqualsLiteral(kPNGImageMime) ||
|
||||
flavorStr.EqualsLiteral(kGIFImageMime)) {
|
||||
// Emulate support for image/jpg
|
||||
if (flavorStr.EqualsLiteral(kJPGImageMime)) {
|
||||
flavorStr.Assign(kJPEGImageMime);
|
||||
}
|
||||
|
||||
MOZ_CLIPBOARD_LOG(" Getting image %s MIME clipboard data\n",
|
||||
flavorStr.get());
|
||||
|
||||
auto clipboardData =
|
||||
mContext->GetClipboardData(flavorStr.get(), aWhichClipboard);
|
||||
if (!clipboardData) {
|
||||
MOZ_CLIPBOARD_LOG(" %s type is missing\n", flavorStr.get());
|
||||
continue;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIInputStream> byteStream;
|
||||
NS_NewByteInputStream(getter_AddRefs(byteStream), clipboardData.AsSpan(),
|
||||
NS_ASSIGNMENT_COPY);
|
||||
aTransferable->SetTransferData(flavorStr.get(), byteStream);
|
||||
MOZ_CLIPBOARD_LOG(" got %s MIME data\n", flavorStr.get());
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Special case text/plain since we can convert any
|
||||
// string into text/plain
|
||||
if (flavorStr.EqualsLiteral(kTextMime)) {
|
||||
MOZ_CLIPBOARD_LOG(" Getting text %s MIME clipboard data\n",
|
||||
flavorStr.get());
|
||||
|
||||
auto clipboardData = mContext->GetClipboardText(aWhichClipboard);
|
||||
if (!clipboardData) {
|
||||
MOZ_CLIPBOARD_LOG(" failed to get text data\n");
|
||||
// If the type was text/plain and we couldn't get
|
||||
// text off the clipboard, run the next loop
|
||||
// iteration.
|
||||
continue;
|
||||
}
|
||||
|
||||
// Convert utf-8 into our text format.
|
||||
NS_ConvertUTF8toUTF16 ucs2string(clipboardData.get());
|
||||
SetTransferableData(aTransferable, flavorStr,
|
||||
(const char*)ucs2string.BeginReading(),
|
||||
ucs2string.Length() * 2);
|
||||
|
||||
MOZ_CLIPBOARD_LOG(" got text data, length %zd\n", ucs2string.Length());
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (flavorStr.EqualsLiteral(kFileMime)) {
|
||||
MOZ_CLIPBOARD_LOG(" Getting %s file clipboard data\n",
|
||||
flavorStr.get());
|
||||
|
||||
auto clipboardData =
|
||||
mContext->GetClipboardData(kURIListMime, aWhichClipboard);
|
||||
if (!clipboardData) {
|
||||
MOZ_CLIPBOARD_LOG(" text/uri-list type is missing\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
nsDependentCSubstring fileName(clipboardData.AsSpan());
|
||||
if (!TransferableSetFile(aTransferable, fileName)) {
|
||||
continue;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
MOZ_CLIPBOARD_LOG(" Getting %s MIME clipboard data\n", flavorStr.get());
|
||||
|
||||
auto clipboardData =
|
||||
mContext->GetClipboardData(flavor.get(), aWhichClipboard);
|
||||
mContext->GetClipboardData(flavorStr.get(), aWhichClipboard);
|
||||
|
||||
#ifdef MOZ_LOGGING
|
||||
if (!clipboardData) {
|
||||
MOZ_CLIPBOARD_LOG(" %s type is missing\n", flavor.get());
|
||||
return nsCOMPtr<nsISupports>{};
|
||||
MOZ_CLIPBOARD_LOG(" %s type is missing\n", flavorStr.get());
|
||||
}
|
||||
#endif
|
||||
|
||||
nsCOMPtr<nsIInputStream> byteStream;
|
||||
NS_NewByteInputStream(getter_AddRefs(byteStream), clipboardData.AsSpan(),
|
||||
NS_ASSIGNMENT_COPY);
|
||||
if (clipboardData) {
|
||||
MOZ_CLIPBOARD_LOG(" got %s mime type data.\n", flavorStr.get());
|
||||
|
||||
MOZ_CLIPBOARD_LOG(" got %s MIME data\n", flavor.get());
|
||||
return nsCOMPtr<nsISupports>(std::move(byteStream));
|
||||
}
|
||||
|
||||
// Special case text/plain since we can convert any
|
||||
// string into text/plain
|
||||
if (aFlavor.EqualsLiteral(kTextMime)) {
|
||||
MOZ_CLIPBOARD_LOG(" Getting text %s MIME clipboard data\n",
|
||||
PromiseFlatCString(aFlavor).get());
|
||||
|
||||
auto clipboardData = mContext->GetClipboardText(aWhichClipboard);
|
||||
if (!clipboardData) {
|
||||
MOZ_CLIPBOARD_LOG(" failed to get text data\n");
|
||||
// If the type was text/plain and we couldn't get
|
||||
// text off the clipboard, run the next loop
|
||||
// iteration.
|
||||
return nsCOMPtr<nsISupports>{};
|
||||
// Special case text/html since we can convert into UCS2
|
||||
if (flavorStr.EqualsLiteral(kHTMLMime)) {
|
||||
if (!TransferableSetHTML(aTransferable, clipboardData.AsSpan())) {
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
auto span = clipboardData.AsSpan();
|
||||
SetTransferableData(aTransferable, flavorStr, span.data(),
|
||||
span.Length());
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Convert utf-8 into our text format.
|
||||
NS_ConvertUTF8toUTF16 ucs2string(clipboardData.get());
|
||||
|
||||
nsCOMPtr<nsISupports> wrapper;
|
||||
nsPrimitiveHelpers::CreatePrimitiveForData(
|
||||
aFlavor, (const char*)ucs2string.BeginReading(),
|
||||
ucs2string.Length() * 2, getter_AddRefs(wrapper));
|
||||
|
||||
MOZ_CLIPBOARD_LOG(" got text data, length %zd\n", ucs2string.Length());
|
||||
return wrapper;
|
||||
}
|
||||
|
||||
if (aFlavor.EqualsLiteral(kFileMime)) {
|
||||
MOZ_CLIPBOARD_LOG(" Getting file %s MIME clipboard data\n",
|
||||
PromiseFlatCString(aFlavor).get());
|
||||
|
||||
auto clipboardData =
|
||||
mContext->GetClipboardData(kURIListMime, aWhichClipboard);
|
||||
if (!clipboardData) {
|
||||
MOZ_CLIPBOARD_LOG(" text/uri-list type is missing\n");
|
||||
return nsCOMPtr<nsISupports>{};
|
||||
}
|
||||
|
||||
nsDependentCSubstring fileName(clipboardData.AsSpan());
|
||||
if (nsCOMPtr<nsIFile> file = GetFileData(fileName)) {
|
||||
MOZ_CLIPBOARD_LOG(" got file data\n");
|
||||
return nsCOMPtr<nsISupports>(std::move(file));
|
||||
}
|
||||
|
||||
MOZ_CLIPBOARD_LOG(" failed to get file data\n");
|
||||
return nsCOMPtr<nsISupports>{};
|
||||
}
|
||||
|
||||
MOZ_CLIPBOARD_LOG(" Getting %s MIME clipboard data\n",
|
||||
PromiseFlatCString(aFlavor).get());
|
||||
|
||||
auto clipboardData = mContext->GetClipboardData(
|
||||
PromiseFlatCString(aFlavor).get(), aWhichClipboard);
|
||||
if (!clipboardData) {
|
||||
MOZ_CLIPBOARD_LOG(" failed to get clipboard content.\n");
|
||||
return nsCOMPtr<nsISupports>{};
|
||||
}
|
||||
|
||||
MOZ_CLIPBOARD_LOG(" got %s mime type data.\n",
|
||||
PromiseFlatCString(aFlavor).get());
|
||||
|
||||
// Special case text/html since we can convert into UCS2
|
||||
auto span = clipboardData.AsSpan();
|
||||
if (aFlavor.EqualsLiteral(kHTMLMime)) {
|
||||
return nsCOMPtr<nsISupports>(GetHTMLData(span));
|
||||
}
|
||||
|
||||
nsCOMPtr<nsISupports> wrapper;
|
||||
nsPrimitiveHelpers::CreatePrimitiveForData(
|
||||
aFlavor, span.data(), span.Length(), getter_AddRefs(wrapper));
|
||||
return wrapper;
|
||||
MOZ_CLIPBOARD_LOG(" failed to get clipboard content.\n");
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
enum DataType {
|
||||
@@ -623,14 +690,17 @@ enum DataType {
|
||||
};
|
||||
|
||||
struct DataCallbackHandler {
|
||||
nsBaseClipboard::GetNativeDataCallback mDataCallback;
|
||||
RefPtr<nsITransferable> mTransferable;
|
||||
nsBaseClipboard::GetDataCallback mDataCallback;
|
||||
nsCString mMimeType;
|
||||
DataType mDataType;
|
||||
|
||||
DataCallbackHandler(nsBaseClipboard::GetNativeDataCallback&& aDataCallback,
|
||||
const nsACString& aMimeType,
|
||||
DataType aDataType = DATATYPE_RAW)
|
||||
: mDataCallback(std::move(aDataCallback)),
|
||||
explicit DataCallbackHandler(RefPtr<nsITransferable> aTransferable,
|
||||
nsBaseClipboard::GetDataCallback&& aDataCallback,
|
||||
const char* aMimeType,
|
||||
DataType aDataType = DATATYPE_RAW)
|
||||
: mTransferable(std::move(aTransferable)),
|
||||
mDataCallback(std::move(aDataCallback)),
|
||||
mMimeType(aMimeType),
|
||||
mDataType(aDataType) {
|
||||
MOZ_COUNT_CTOR(DataCallbackHandler);
|
||||
@@ -643,9 +713,9 @@ struct DataCallbackHandler {
|
||||
}
|
||||
};
|
||||
|
||||
static void AsyncGetTextImpl(
|
||||
int32_t aWhichClipboard,
|
||||
nsBaseClipboard::GetNativeDataCallback&& aCallback) {
|
||||
static void AsyncGetTextImpl(nsITransferable* aTransferable,
|
||||
int32_t aWhichClipboard,
|
||||
nsBaseClipboard::GetDataCallback&& aCallback) {
|
||||
MOZ_CLIPBOARD_LOG("AsyncGetText() type '%s'",
|
||||
aWhichClipboard == nsClipboard::kSelectionClipboard
|
||||
? "primary"
|
||||
@@ -661,41 +731,47 @@ static void AsyncGetTextImpl(
|
||||
size_t dataLength = aText ? strlen(aText) : 0;
|
||||
if (dataLength <= 0) {
|
||||
MOZ_CLIPBOARD_LOG(" quit, text is not available");
|
||||
ref->mDataCallback(nsCOMPtr<nsISupports>{});
|
||||
ref->mDataCallback(NS_OK);
|
||||
return;
|
||||
}
|
||||
|
||||
// Convert utf-8 into our unicode format.
|
||||
NS_ConvertUTF8toUTF16 utf16string(aText, dataLength);
|
||||
nsLiteralCString flavor(kTextMime);
|
||||
|
||||
nsCOMPtr<nsISupports> wrapper;
|
||||
nsPrimitiveHelpers::CreatePrimitiveForData(
|
||||
flavor, (const char*)utf16string.BeginReading(),
|
||||
utf16string.Length() * 2, getter_AddRefs(wrapper));
|
||||
|
||||
SetTransferableData(ref->mTransferable, flavor,
|
||||
(const char*)utf16string.BeginReading(),
|
||||
utf16string.Length() * 2);
|
||||
MOZ_CLIPBOARD_LOG(" text is set, length = %d", (int)dataLength);
|
||||
ref->mDataCallback(wrapper);
|
||||
ref->mDataCallback(NS_OK);
|
||||
},
|
||||
new DataCallbackHandler(std::move(aCallback),
|
||||
nsLiteralCString(kTextMime)));
|
||||
new DataCallbackHandler(aTransferable, std::move(aCallback), kTextMime));
|
||||
}
|
||||
|
||||
static void AsyncGetDataImpl(
|
||||
int32_t aWhichClipboard, const nsACString& aMimeType, DataType aDataType,
|
||||
nsBaseClipboard::GetNativeDataCallback&& aCallback) {
|
||||
static void AsyncGetDataImpl(nsITransferable* aTransferable,
|
||||
int32_t aWhichClipboard, const char* aMimeType,
|
||||
DataType aDataType,
|
||||
nsBaseClipboard::GetDataCallback&& aCallback) {
|
||||
MOZ_CLIPBOARD_LOG("AsyncGetData() type '%s'",
|
||||
aWhichClipboard == nsClipboard::kSelectionClipboard
|
||||
? "primary"
|
||||
: "clipboard");
|
||||
|
||||
const char* gtkMIMEType = nullptr;
|
||||
switch (aDataType) {
|
||||
case DATATYPE_FILE:
|
||||
// Don't ask Gtk for application/x-moz-file
|
||||
gtkMIMEType = kURIListMime;
|
||||
break;
|
||||
case DATATYPE_IMAGE:
|
||||
case DATATYPE_HTML:
|
||||
case DATATYPE_RAW:
|
||||
gtkMIMEType = aMimeType;
|
||||
break;
|
||||
}
|
||||
|
||||
gtk_clipboard_request_contents(
|
||||
gtk_clipboard_get(GetSelectionAtom(aWhichClipboard)),
|
||||
// Don't ask Gtk for application/x-moz-file.
|
||||
gdk_atom_intern((aDataType == DATATYPE_FILE)
|
||||
? kURIListMime
|
||||
: PromiseFlatCString(aMimeType).get(),
|
||||
FALSE),
|
||||
gdk_atom_intern(gtkMIMEType, FALSE),
|
||||
[](GtkClipboard* aClipboard, GtkSelectionData* aSelection,
|
||||
gpointer aData) -> void {
|
||||
UniquePtr<DataCallbackHandler> ref(
|
||||
@@ -705,120 +781,130 @@ static void AsyncGetDataImpl(
|
||||
|
||||
int dataLength = gtk_selection_data_get_length(aSelection);
|
||||
if (dataLength <= 0) {
|
||||
ref->mDataCallback(nsCOMPtr<nsISupports>{});
|
||||
ref->mDataCallback(NS_OK);
|
||||
return;
|
||||
}
|
||||
const char* data = (const char*)gtk_selection_data_get_data(aSelection);
|
||||
if (!data) {
|
||||
ref->mDataCallback(nsCOMPtr<nsISupports>{});
|
||||
ref->mDataCallback(NS_OK);
|
||||
return;
|
||||
}
|
||||
switch (ref->mDataType) {
|
||||
case DATATYPE_IMAGE: {
|
||||
MOZ_CLIPBOARD_LOG(" get image clipboard data");
|
||||
MOZ_CLIPBOARD_LOG(" set image clipboard data");
|
||||
nsCOMPtr<nsIInputStream> byteStream;
|
||||
NS_NewByteInputStream(getter_AddRefs(byteStream),
|
||||
Span(data, dataLength), NS_ASSIGNMENT_COPY);
|
||||
ref->mDataCallback(nsCOMPtr<nsISupports>(byteStream));
|
||||
return;
|
||||
ref->mTransferable->SetTransferData(ref->mMimeType.get(),
|
||||
byteStream);
|
||||
break;
|
||||
}
|
||||
case DATATYPE_FILE: {
|
||||
MOZ_CLIPBOARD_LOG(" get file clipboard data");
|
||||
nsDependentCSubstring uriList(data, dataLength);
|
||||
if (nsCOMPtr<nsIFile> file = GetFileData(uriList)) {
|
||||
MOZ_CLIPBOARD_LOG(" successfully get file data\n");
|
||||
ref->mDataCallback(nsCOMPtr<nsISupports>(file));
|
||||
return;
|
||||
}
|
||||
MOZ_CLIPBOARD_LOG(" set file clipboard data");
|
||||
nsDependentCSubstring file(data, dataLength);
|
||||
TransferableSetFile(ref->mTransferable, file);
|
||||
break;
|
||||
}
|
||||
case DATATYPE_HTML: {
|
||||
MOZ_CLIPBOARD_LOG(" html clipboard data");
|
||||
Span dataSpan(data, dataLength);
|
||||
if (nsCOMPtr<nsISupports> data = GetHTMLData(dataSpan)) {
|
||||
MOZ_CLIPBOARD_LOG(" successfully get HTML data\n");
|
||||
ref->mDataCallback(nsCOMPtr<nsISupports>(data));
|
||||
return;
|
||||
}
|
||||
TransferableSetHTML(ref->mTransferable, dataSpan);
|
||||
break;
|
||||
}
|
||||
case DATATYPE_RAW: {
|
||||
MOZ_CLIPBOARD_LOG(" raw clipboard data %s", ref->mMimeType.get());
|
||||
|
||||
nsCOMPtr<nsISupports> wrapper;
|
||||
nsPrimitiveHelpers::CreatePrimitiveForData(
|
||||
ref->mMimeType, data, dataLength, getter_AddRefs(wrapper));
|
||||
ref->mDataCallback(nsCOMPtr<nsISupports>(wrapper));
|
||||
return;
|
||||
SetTransferableData(ref->mTransferable, ref->mMimeType, data,
|
||||
dataLength);
|
||||
break;
|
||||
}
|
||||
}
|
||||
ref->mDataCallback(nsCOMPtr<nsISupports>{});
|
||||
ref->mDataCallback(NS_OK);
|
||||
},
|
||||
new DataCallbackHandler(std::move(aCallback), aMimeType, aDataType));
|
||||
new DataCallbackHandler(aTransferable, std::move(aCallback), aMimeType,
|
||||
aDataType));
|
||||
}
|
||||
|
||||
static void AsyncGetDataFlavor(
|
||||
int32_t aWhichClipboard, const nsACString& aFlavorStr,
|
||||
nsBaseClipboard::GetNativeDataCallback&& aCallback) {
|
||||
static void AsyncGetDataFlavor(nsITransferable* aTransferable,
|
||||
int32_t aWhichClipboard, nsCString& aFlavorStr,
|
||||
nsBaseClipboard::GetDataCallback&& aCallback) {
|
||||
if (aFlavorStr.EqualsLiteral(kJPEGImageMime) ||
|
||||
aFlavorStr.EqualsLiteral(kJPGImageMime) ||
|
||||
aFlavorStr.EqualsLiteral(kPNGImageMime) ||
|
||||
aFlavorStr.EqualsLiteral(kGIFImageMime)) {
|
||||
// Emulate support for image/jpg
|
||||
nsAutoCString flavor(aFlavorStr.EqualsLiteral(kJPGImageMime)
|
||||
? kJPEGImageMime
|
||||
: PromiseFlatCString(aFlavorStr).get());
|
||||
MOZ_CLIPBOARD_LOG(" Getting image %s MIME clipboard data", flavor.get());
|
||||
AsyncGetDataImpl(aWhichClipboard, flavor, DATATYPE_IMAGE,
|
||||
std::move(aCallback));
|
||||
if (aFlavorStr.EqualsLiteral(kJPGImageMime)) {
|
||||
aFlavorStr.Assign(kJPEGImageMime);
|
||||
}
|
||||
MOZ_CLIPBOARD_LOG(" Getting image %s MIME clipboard data",
|
||||
aFlavorStr.get());
|
||||
AsyncGetDataImpl(aTransferable, aWhichClipboard, aFlavorStr.get(),
|
||||
DATATYPE_IMAGE, std::move(aCallback));
|
||||
return;
|
||||
}
|
||||
// Special case text/plain since we can convert any
|
||||
// string into text/plain
|
||||
if (aFlavorStr.EqualsLiteral(kTextMime)) {
|
||||
MOZ_CLIPBOARD_LOG(" Getting unicode clipboard data");
|
||||
AsyncGetTextImpl(aWhichClipboard, std::move(aCallback));
|
||||
AsyncGetTextImpl(aTransferable, aWhichClipboard, std::move(aCallback));
|
||||
return;
|
||||
}
|
||||
if (aFlavorStr.EqualsLiteral(kFileMime)) {
|
||||
MOZ_CLIPBOARD_LOG(" Getting file clipboard data\n");
|
||||
AsyncGetDataImpl(aWhichClipboard, aFlavorStr, DATATYPE_FILE,
|
||||
std::move(aCallback));
|
||||
AsyncGetDataImpl(aTransferable, aWhichClipboard, aFlavorStr.get(),
|
||||
DATATYPE_FILE, std::move(aCallback));
|
||||
return;
|
||||
}
|
||||
if (aFlavorStr.EqualsLiteral(kHTMLMime)) {
|
||||
MOZ_CLIPBOARD_LOG(" Getting HTML clipboard data");
|
||||
AsyncGetDataImpl(aWhichClipboard, aFlavorStr, DATATYPE_HTML,
|
||||
std::move(aCallback));
|
||||
AsyncGetDataImpl(aTransferable, aWhichClipboard, aFlavorStr.get(),
|
||||
DATATYPE_HTML, std::move(aCallback));
|
||||
return;
|
||||
}
|
||||
MOZ_CLIPBOARD_LOG(" Getting raw %s MIME clipboard data\n",
|
||||
PromiseFlatCString(aFlavorStr).get());
|
||||
AsyncGetDataImpl(aWhichClipboard, aFlavorStr, DATATYPE_RAW,
|
||||
std::move(aCallback));
|
||||
MOZ_CLIPBOARD_LOG(" Getting raw %s MIME clipboard data\n", aFlavorStr.get());
|
||||
AsyncGetDataImpl(aTransferable, aWhichClipboard, aFlavorStr.get(),
|
||||
DATATYPE_RAW, std::move(aCallback));
|
||||
}
|
||||
|
||||
void nsClipboard::AsyncGetNativeClipboardData(
|
||||
const nsACString& aFlavor, ClipboardType aWhichClipboard,
|
||||
GetNativeDataCallback&& aCallback) {
|
||||
void nsClipboard::AsyncGetNativeClipboardData(nsITransferable* aTransferable,
|
||||
ClipboardType aWhichClipboard,
|
||||
GetDataCallback&& aCallback) {
|
||||
MOZ_DIAGNOSTIC_ASSERT(aTransferable);
|
||||
MOZ_DIAGNOSTIC_ASSERT(
|
||||
nsIClipboard::IsClipboardTypeSupported(aWhichClipboard));
|
||||
|
||||
MOZ_CLIPBOARD_LOG("nsClipboard::AsyncGetNativeClipboardData (%s) for %s",
|
||||
MOZ_CLIPBOARD_LOG("nsClipboard::AsyncGetNativeClipboardData (%s)",
|
||||
aWhichClipboard == nsClipboard::kSelectionClipboard
|
||||
? "primary"
|
||||
: "clipboard",
|
||||
PromiseFlatCString(aFlavor).get());
|
||||
: "clipboard");
|
||||
nsTArray<nsCString> importedFlavors;
|
||||
nsresult rv = GetTransferableFlavors(aTransferable, importedFlavors);
|
||||
if (NS_FAILED(rv)) {
|
||||
aCallback(rv);
|
||||
return;
|
||||
}
|
||||
|
||||
auto flavorsNum = importedFlavors.Length();
|
||||
if (!flavorsNum) {
|
||||
aCallback(NS_OK);
|
||||
return;
|
||||
}
|
||||
#ifdef MOZ_LOGGING
|
||||
if (flavorsNum > 1) {
|
||||
MOZ_CLIPBOARD_LOG(
|
||||
" Only first MIME type (%s) will be imported from clipboard!",
|
||||
importedFlavors[0].get());
|
||||
}
|
||||
#endif
|
||||
|
||||
// Filter out MIME types on X11 to prevent unwanted conversions,
|
||||
// see Bug 1611407
|
||||
if (widget::GdkIsX11Display()) {
|
||||
AsyncHasNativeClipboardDataMatchingFlavors(
|
||||
nsTArray<nsCString>{PromiseFlatCString(aFlavor)}, aWhichClipboard,
|
||||
[aWhichClipboard,
|
||||
importedFlavors, aWhichClipboard,
|
||||
[aWhichClipboard, transferable = nsCOMPtr{aTransferable},
|
||||
callback = std::move(aCallback)](auto aResultOrError) mutable {
|
||||
if (aResultOrError.isErr()) {
|
||||
callback(Err(aResultOrError.unwrapErr()));
|
||||
callback(aResultOrError.unwrapErr());
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -826,18 +912,19 @@ void nsClipboard::AsyncGetNativeClipboardData(
|
||||
std::move(aResultOrError.unwrap());
|
||||
if (!clipboardFlavors.Length()) {
|
||||
MOZ_CLIPBOARD_LOG(" no flavors in clipboard, quit.");
|
||||
callback(nsCOMPtr<nsISupports>{});
|
||||
callback(NS_OK);
|
||||
return;
|
||||
}
|
||||
|
||||
AsyncGetDataFlavor(aWhichClipboard, clipboardFlavors[0],
|
||||
AsyncGetDataFlavor(transferable, aWhichClipboard, clipboardFlavors[0],
|
||||
std::move(callback));
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// Read clipboard directly on Wayland
|
||||
AsyncGetDataFlavor(aWhichClipboard, aFlavor, std::move(aCallback));
|
||||
AsyncGetDataFlavor(aTransferable, aWhichClipboard, importedFlavors[0],
|
||||
std::move(aCallback));
|
||||
}
|
||||
|
||||
nsresult nsClipboard::EmptyNativeClipboardData(ClipboardType aWhichClipboard) {
|
||||
|
||||
@@ -94,7 +94,7 @@ class nsRetrievalContext {
|
||||
static ClipboardTargets sPrimaryTargets;
|
||||
};
|
||||
|
||||
class nsClipboard final : public nsBaseClipboard, public nsIObserver {
|
||||
class nsClipboard : public nsBaseClipboard, public nsIObserver {
|
||||
public:
|
||||
nsClipboard();
|
||||
|
||||
@@ -121,11 +121,11 @@ class nsClipboard final : public nsBaseClipboard, public nsIObserver {
|
||||
// Implement the native clipboard behavior.
|
||||
NS_IMETHOD SetNativeClipboardData(nsITransferable* aTransferable,
|
||||
ClipboardType aWhichClipboard) override;
|
||||
mozilla::Result<nsCOMPtr<nsISupports>, nsresult> GetNativeClipboardData(
|
||||
const nsACString& aFlavor, ClipboardType aWhichClipboard) override;
|
||||
void AsyncGetNativeClipboardData(const nsACString& aFlavor,
|
||||
NS_IMETHOD GetNativeClipboardData(nsITransferable* aTransferable,
|
||||
ClipboardType aWhichClipboard) override;
|
||||
void AsyncGetNativeClipboardData(nsITransferable* aTransferable,
|
||||
ClipboardType aWhichClipboard,
|
||||
GetNativeDataCallback&& aCallback) override;
|
||||
GetDataCallback&& aCallback) override;
|
||||
nsresult EmptyNativeClipboardData(ClipboardType aWhichClipboard) override;
|
||||
mozilla::Result<bool, nsresult> HasNativeClipboardDataMatchingFlavors(
|
||||
const nsTArray<nsCString>& aFlavorList,
|
||||
@@ -144,7 +144,8 @@ class nsClipboard final : public nsBaseClipboard, public nsIObserver {
|
||||
void ClearTransferable(int32_t aWhichClipboard);
|
||||
void ClearCachedTargets(int32_t aWhichClipboard);
|
||||
|
||||
bool HasSuitableData(int32_t aWhichClipboard, const nsACString& aFlavor);
|
||||
bool FilterImportedFlavors(int32_t aWhichClipboard,
|
||||
nsTArray<nsCString>& aFlavors);
|
||||
|
||||
// Hang on to our transferables so we can transfer data when asked.
|
||||
nsCOMPtr<nsITransferable> mSelectionTransferable;
|
||||
|
||||
@@ -66,34 +66,51 @@ HeadlessClipboard::SetNativeClipboardData(nsITransferable* aTransferable,
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
mozilla::Result<nsCOMPtr<nsISupports>, nsresult>
|
||||
HeadlessClipboard::GetNativeClipboardData(const nsACString& aFlavor,
|
||||
NS_IMETHODIMP
|
||||
HeadlessClipboard::GetNativeClipboardData(nsITransferable* aTransferable,
|
||||
ClipboardType aWhichClipboard) {
|
||||
MOZ_DIAGNOSTIC_ASSERT(aTransferable);
|
||||
MOZ_DIAGNOSTIC_ASSERT(
|
||||
nsIClipboard::IsClipboardTypeSupported(aWhichClipboard));
|
||||
|
||||
nsTArray<nsCString> flavors;
|
||||
nsresult rv = aTransferable->FlavorsTransferableCanImport(flavors);
|
||||
if (NS_FAILED(rv)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
auto& clipboard = mClipboards[aWhichClipboard];
|
||||
MOZ_ASSERT(clipboard);
|
||||
|
||||
if (!aFlavor.EqualsLiteral(kTextMime) && !aFlavor.EqualsLiteral(kHTMLMime)) {
|
||||
return nsCOMPtr<nsISupports>{};
|
||||
for (const auto& flavor : flavors) {
|
||||
if (!flavor.EqualsLiteral(kTextMime) && !flavor.EqualsLiteral(kHTMLMime)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
bool isText = flavor.EqualsLiteral(kTextMime);
|
||||
if (!(isText ? clipboard->HasText() : clipboard->HasHTML())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsISupportsString> dataWrapper =
|
||||
do_CreateInstance(NS_SUPPORTS_STRING_CONTRACTID, &rv);
|
||||
rv = dataWrapper->SetData(isText ? clipboard->GetText()
|
||||
: clipboard->GetHTML());
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
continue;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsISupports> genericDataWrapper = do_QueryInterface(dataWrapper);
|
||||
rv = aTransferable->SetTransferData(flavor.get(), genericDataWrapper);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// XXX Other platforms only fill the first available type, too.
|
||||
break;
|
||||
}
|
||||
|
||||
bool isText = aFlavor.EqualsLiteral(kTextMime);
|
||||
if (!(isText ? clipboard->HasText() : clipboard->HasHTML())) {
|
||||
return nsCOMPtr<nsISupports>{};
|
||||
}
|
||||
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsISupportsString> dataWrapper =
|
||||
do_CreateInstance(NS_SUPPORTS_STRING_CONTRACTID, &rv);
|
||||
rv = dataWrapper->SetData(isText ? clipboard->GetText()
|
||||
: clipboard->GetHTML());
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return nsCOMPtr<nsISupports>{};
|
||||
}
|
||||
|
||||
return nsCOMPtr<nsISupports>(std::move(dataWrapper));
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult HeadlessClipboard::EmptyNativeClipboardData(
|
||||
|
||||
@@ -28,8 +28,8 @@ class HeadlessClipboard final : public nsBaseClipboard {
|
||||
// Implement the native clipboard behavior.
|
||||
NS_IMETHOD SetNativeClipboardData(nsITransferable* aTransferable,
|
||||
ClipboardType aWhichClipboard) override;
|
||||
mozilla::Result<nsCOMPtr<nsISupports>, nsresult> GetNativeClipboardData(
|
||||
const nsACString& aFlavor, ClipboardType aWhichClipboard) override;
|
||||
NS_IMETHOD GetNativeClipboardData(nsITransferable* aTransferable,
|
||||
ClipboardType aWhichClipboard) override;
|
||||
nsresult EmptyNativeClipboardData(ClipboardType aWhichClipboard) override;
|
||||
mozilla::Result<bool, nsresult> HasNativeClipboardDataMatchingFlavors(
|
||||
const nsTArray<nsCString>& aFlavorList,
|
||||
|
||||
@@ -463,26 +463,10 @@ NS_IMETHODIMP nsBaseClipboard::GetData(
|
||||
// at this point we can't satisfy the request from cache data so let's look
|
||||
// for things other people put on the system clipboard
|
||||
}
|
||||
|
||||
nsTArray<nsCString> flavors;
|
||||
nsresult rv = aTransferable->FlavorsTransferableCanImport(flavors);
|
||||
nsresult rv = GetNativeClipboardData(aTransferable, aWhichClipboard);
|
||||
if (NS_FAILED(rv)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
return rv;
|
||||
}
|
||||
|
||||
for (const auto& flavor : flavors) {
|
||||
auto dataOrError = GetNativeClipboardData(flavor, aWhichClipboard);
|
||||
if (dataOrError.isErr()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (dataOrError.inspect()) {
|
||||
aTransferable->SetTransferData(flavor.get(), dataOrError.inspect());
|
||||
// XXX Maybe try to fill in more types? Is there a point?
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!mozilla::contentanalysis::ContentAnalysis::
|
||||
CheckClipboardContentAnalysisSync(this, aWindowContext->Canonical(),
|
||||
aTransferable, aWhichClipboard)) {
|
||||
@@ -889,9 +873,9 @@ void nsBaseClipboard::AsyncHasNativeClipboardDataMatchingFlavors(
|
||||
}
|
||||
|
||||
void nsBaseClipboard::AsyncGetNativeClipboardData(
|
||||
const nsACString& aFlavor, ClipboardType aWhichClipboard,
|
||||
GetNativeDataCallback&& aCallback) {
|
||||
aCallback(GetNativeClipboardData(aFlavor, aWhichClipboard));
|
||||
nsITransferable* aTransferable, ClipboardType aWhichClipboard,
|
||||
GetDataCallback&& aCallback) {
|
||||
aCallback(GetNativeClipboardData(aTransferable, aWhichClipboard));
|
||||
}
|
||||
|
||||
void nsBaseClipboard::ClearClipboardCache(ClipboardType aClipboardType) {
|
||||
@@ -1067,8 +1051,8 @@ NS_IMETHODIMP nsBaseClipboard::ClipboardDataSnapshot::GetData(
|
||||
|
||||
// Since this is an async operation, we need to check if the data is still
|
||||
// valid after we get the result.
|
||||
GetDataInternal(
|
||||
std::move(flavors), 0, aTransferable,
|
||||
mClipboard->AsyncGetNativeClipboardData(
|
||||
aTransferable, mClipboardType,
|
||||
[callback = nsCOMPtr{aCallback}, self = RefPtr{this},
|
||||
transferable = nsCOMPtr{aTransferable},
|
||||
contentAnalysisCallback =
|
||||
@@ -1147,18 +1131,9 @@ NS_IMETHODIMP nsBaseClipboard::ClipboardDataSnapshot::GetDataSync(
|
||||
// for things other people put on the system clipboard.
|
||||
}
|
||||
|
||||
for (const auto& flavor : flavors) {
|
||||
auto dataOrError =
|
||||
mClipboard->GetNativeClipboardData(flavor, mClipboardType);
|
||||
if (dataOrError.isErr()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (dataOrError.inspect()) {
|
||||
aTransferable->SetTransferData(flavor.get(), dataOrError.inspect());
|
||||
// XXX Maybe try to fill in more types? Is there a point?
|
||||
break;
|
||||
}
|
||||
rv = mClipboard->GetNativeClipboardData(aTransferable, mClipboardType);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
bool shouldAllowContent = mozilla::contentanalysis::ContentAnalysis::
|
||||
@@ -1207,46 +1182,6 @@ bool nsBaseClipboard::ClipboardDataSnapshot::IsValid() {
|
||||
return true;
|
||||
}
|
||||
|
||||
void nsBaseClipboard::ClipboardDataSnapshot::GetDataInternal(
|
||||
nsTArray<nsCString>&& aTypes, nsTArray<nsCString>::index_type aIndex,
|
||||
nsITransferable* aTransferable, GetDataInternalCallback&& aCallback) {
|
||||
MOZ_ASSERT(aIndex < aTypes.Length());
|
||||
|
||||
// Since this is an async operation, we need to check if the data is still
|
||||
// valid after we get the result.
|
||||
mClipboard->AsyncGetNativeClipboardData(
|
||||
aTypes[aIndex], mClipboardType,
|
||||
[self = RefPtr{this}, types = std::move(aTypes), index = aIndex,
|
||||
transferable = nsCOMPtr{aTransferable}, callback = std::move(aCallback)](
|
||||
mozilla::Result<nsCOMPtr<nsISupports>, nsresult> aResult) mutable {
|
||||
MOZ_ASSERT(index < types.Length());
|
||||
|
||||
// `IsValid()` checks the clipboard sequence number to ensure the data
|
||||
// we are requesting is still valid.
|
||||
if (!self->IsValid()) {
|
||||
callback(NS_ERROR_NOT_AVAILABLE);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!aResult.isErr() && aResult.inspect()) {
|
||||
MOZ_ASSERT(index < types.Length());
|
||||
transferable->SetTransferData(types[index].get(), aResult.inspect());
|
||||
callback(NS_OK);
|
||||
return;
|
||||
}
|
||||
|
||||
// No more types to try.
|
||||
if (++index >= types.Length()) {
|
||||
callback(NS_OK);
|
||||
return;
|
||||
}
|
||||
|
||||
// Recursively call GetDataInternal to try the next type.
|
||||
self->GetDataInternal(std::move(types), index, transferable,
|
||||
std::move(callback));
|
||||
});
|
||||
}
|
||||
|
||||
NS_IMPL_ISUPPORTS(nsBaseClipboard::ClipboardPopulatedDataSnapshot,
|
||||
nsIClipboardDataSnapshot)
|
||||
|
||||
|
||||
@@ -76,8 +76,7 @@ class nsBaseClipboard : public nsIClipboard {
|
||||
mozilla::dom::WindowContext* aRequestingWindowContext,
|
||||
nsIClipboardGetDataSnapshotCallback* aCallback);
|
||||
|
||||
using GetNativeDataCallback = mozilla::MoveOnlyFunction<void(
|
||||
mozilla::Result<nsCOMPtr<nsISupports>, nsresult>)>;
|
||||
using GetDataCallback = mozilla::MoveOnlyFunction<void(nsresult)>;
|
||||
using HasMatchingFlavorsCallback = mozilla::MoveOnlyFunction<void(
|
||||
mozilla::Result<nsTArray<nsCString>, nsresult>)>;
|
||||
|
||||
@@ -105,12 +104,11 @@ class nsBaseClipboard : public nsIClipboard {
|
||||
// Implement the native clipboard behavior.
|
||||
NS_IMETHOD SetNativeClipboardData(nsITransferable* aTransferable,
|
||||
ClipboardType aWhichClipboard) = 0;
|
||||
virtual mozilla::Result<nsCOMPtr<nsISupports>, nsresult>
|
||||
GetNativeClipboardData(const nsACString& aFlavor,
|
||||
ClipboardType aWhichClipboard) = 0;
|
||||
virtual void AsyncGetNativeClipboardData(const nsACString& aFlavor,
|
||||
NS_IMETHOD GetNativeClipboardData(nsITransferable* aTransferable,
|
||||
ClipboardType aWhichClipboard) = 0;
|
||||
virtual void AsyncGetNativeClipboardData(nsITransferable* aTransferable,
|
||||
ClipboardType aWhichClipboard,
|
||||
GetNativeDataCallback&& aCallback);
|
||||
GetDataCallback&& aCallback);
|
||||
virtual nsresult EmptyNativeClipboardData(ClipboardType aWhichClipboard) = 0;
|
||||
virtual mozilla::Result<bool, nsresult> HasNativeClipboardDataMatchingFlavors(
|
||||
const nsTArray<nsCString>& aFlavorList,
|
||||
@@ -170,12 +168,6 @@ class nsBaseClipboard : public nsIClipboard {
|
||||
virtual ~ClipboardDataSnapshot() = default;
|
||||
bool IsValid();
|
||||
|
||||
using GetDataInternalCallback = mozilla::MoveOnlyFunction<void(nsresult)>;
|
||||
void GetDataInternal(nsTArray<nsCString>&& aTypes,
|
||||
nsTArray<nsCString>::index_type aIndex,
|
||||
nsITransferable* aTransferable,
|
||||
GetDataInternalCallback&& aCallback);
|
||||
|
||||
// The clipboard type defined in nsIClipboard.
|
||||
const nsIClipboard::ClipboardType mClipboardType;
|
||||
// The sequence number associated with the clipboard content for this
|
||||
|
||||
@@ -165,7 +165,7 @@ interface nsIClipboard : nsISupports
|
||||
/**
|
||||
* Filters the flavors aTransferable can import (see
|
||||
* `nsITransferable::flavorsTransferableCanImport`) and gets the data for the
|
||||
* first available flavor. That data is set for aTransferable.
|
||||
* first flavor. That data is set for aTransferable.
|
||||
*
|
||||
* @param aTransferable The transferable
|
||||
* @param aWhichClipboard Specifies the clipboard to which this operation applies.
|
||||
|
||||
@@ -960,125 +960,6 @@ nsresult nsClipboard::GetNativeDataOffClipboard(IDataObject* aDataObject,
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
mozilla::Result<nsCOMPtr<nsISupports>, nsresult>
|
||||
nsClipboard::GetDataFromDataObject(IDataObject* aDataObject, UINT anIndex,
|
||||
nsIWidget* aWindow,
|
||||
const nsCString& aFlavor) {
|
||||
MOZ_CLIPBOARD_LOG("%s", __FUNCTION__);
|
||||
|
||||
UINT format = GetFormat(aFlavor.get());
|
||||
|
||||
// Try to get the data using the desired flavor. This might fail, but all is
|
||||
// not lost.
|
||||
void* data = nullptr;
|
||||
uint32_t dataLen = 0;
|
||||
bool dataFound = false;
|
||||
if (nullptr != aDataObject) {
|
||||
if (NS_SUCCEEDED(GetNativeDataOffClipboard(
|
||||
aDataObject, anIndex, format, aFlavor.get(), &data, &dataLen))) {
|
||||
dataFound = true;
|
||||
}
|
||||
} else if (nullptr != aWindow) {
|
||||
if (NS_SUCCEEDED(GetNativeDataOffClipboard(aWindow, anIndex, format, &data,
|
||||
&dataLen))) {
|
||||
dataFound = true;
|
||||
}
|
||||
}
|
||||
|
||||
// This is our second chance to try to find some data, having not found it
|
||||
// when directly asking for the flavor. Let's try digging around in other
|
||||
// flavors to help satisfy our craving for data.
|
||||
if (!dataFound) {
|
||||
if (aFlavor.EqualsLiteral(kTextMime)) {
|
||||
dataFound =
|
||||
FindUnicodeFromPlainText(aDataObject, anIndex, &data, &dataLen);
|
||||
} else if (aFlavor.EqualsLiteral(kURLMime)) {
|
||||
// drags from other windows apps expose the native
|
||||
// CFSTR_INETURL{A,W} flavor
|
||||
dataFound = FindURLFromNativeURL(aDataObject, anIndex, &data, &dataLen);
|
||||
if (!dataFound) {
|
||||
dataFound = FindURLFromLocalFile(aDataObject, anIndex, &data, &dataLen);
|
||||
}
|
||||
} else {
|
||||
mozilla::Maybe<UINT> secondaryFormat = GetSecondaryFormat(aFlavor.get());
|
||||
if (secondaryFormat) {
|
||||
// Fall back to secondary format
|
||||
dataFound = NS_SUCCEEDED(GetNativeDataOffClipboard(
|
||||
aDataObject, anIndex, secondaryFormat.value(), aFlavor.get(), &data,
|
||||
&dataLen));
|
||||
}
|
||||
}
|
||||
} // if we try one last ditch effort to find our data
|
||||
|
||||
if (!dataFound) {
|
||||
return nsCOMPtr<nsISupports>{};
|
||||
}
|
||||
|
||||
// Hopefully by this point we've found it and can go about our business
|
||||
nsCOMPtr<nsISupports> genericDataWrapper;
|
||||
if (aFlavor.EqualsLiteral(kFileMime)) {
|
||||
// we have a file path in |data|. Create an nsLocalFile object.
|
||||
nsDependentString filepath(reinterpret_cast<char16_t*>(data));
|
||||
nsCOMPtr<nsIFile> file;
|
||||
if (NS_SUCCEEDED(NS_NewLocalFile(filepath, getter_AddRefs(file)))) {
|
||||
genericDataWrapper = do_QueryInterface(file);
|
||||
}
|
||||
free(data);
|
||||
} else if (aFlavor.EqualsLiteral(kNativeHTMLMime)) {
|
||||
uint32_t dummy;
|
||||
// the editor folks want CF_HTML exactly as it's on the clipboard, no
|
||||
// conversions, no fancy stuff. Pull it off the clipboard, stuff it into
|
||||
// a wrapper and hand it back to them.
|
||||
if (FindPlatformHTML(aDataObject, anIndex, &data, &dummy, &dataLen)) {
|
||||
nsPrimitiveHelpers::CreatePrimitiveForData(
|
||||
aFlavor, data, dataLen, getter_AddRefs(genericDataWrapper));
|
||||
}
|
||||
free(data);
|
||||
} else if (aFlavor.EqualsLiteral(kHTMLMime)) {
|
||||
uint32_t startOfData = 0;
|
||||
// The JS folks want CF_HTML exactly as it is on the clipboard, but
|
||||
// minus the CF_HTML header index information.
|
||||
// It also needs to be converted to UTF16 and have linebreaks changed.
|
||||
if (FindPlatformHTML(aDataObject, anIndex, &data, &startOfData, &dataLen)) {
|
||||
dataLen -= startOfData;
|
||||
nsPrimitiveHelpers::CreatePrimitiveForCFHTML(
|
||||
static_cast<char*>(data) + startOfData, &dataLen,
|
||||
getter_AddRefs(genericDataWrapper));
|
||||
}
|
||||
free(data);
|
||||
} else if (aFlavor.EqualsLiteral(kJPEGImageMime) ||
|
||||
aFlavor.EqualsLiteral(kJPGImageMime) ||
|
||||
aFlavor.EqualsLiteral(kPNGImageMime)) {
|
||||
nsIInputStream* imageStream = reinterpret_cast<nsIInputStream*>(data);
|
||||
genericDataWrapper = do_QueryInterface(imageStream);
|
||||
NS_IF_RELEASE(imageStream);
|
||||
} else {
|
||||
// Treat custom types as a string of bytes.
|
||||
if (!aFlavor.EqualsLiteral(kCustomTypesMime)) {
|
||||
bool isRTF = aFlavor.EqualsLiteral(kRTFMime);
|
||||
// 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(isRTF, &data,
|
||||
&signedLen);
|
||||
dataLen = signedLen;
|
||||
|
||||
if (isRTF) {
|
||||
// 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(
|
||||
aFlavor, data, dataLen, getter_AddRefs(genericDataWrapper));
|
||||
free(data);
|
||||
}
|
||||
|
||||
return std::move(genericDataWrapper);
|
||||
}
|
||||
|
||||
nsresult nsClipboard::GetDataFromDataObject(IDataObject* aDataObject,
|
||||
UINT anIndex, nsIWidget* aWindow,
|
||||
nsITransferable* aTransferable) {
|
||||
@@ -1089,10 +970,12 @@ nsresult nsClipboard::GetDataFromDataObject(IDataObject* aDataObject,
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
nsresult res = NS_ERROR_FAILURE;
|
||||
|
||||
// get flavor list that includes all flavors that can be written (including
|
||||
// ones obtained through conversion)
|
||||
nsTArray<nsCString> flavors;
|
||||
nsresult res = aTransferable->FlavorsTransferableCanImport(flavors);
|
||||
res = aTransferable->FlavorsTransferableCanImport(flavors);
|
||||
if (NS_FAILED(res)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
@@ -1100,22 +983,137 @@ nsresult nsClipboard::GetDataFromDataObject(IDataObject* aDataObject,
|
||||
// Walk through flavors and see which flavor is on the clipboard them on the
|
||||
// native clipboard,
|
||||
for (uint32_t i = 0; i < flavors.Length(); i++) {
|
||||
const nsCString& flavorStr = flavors[i];
|
||||
nsCString& flavorStr = flavors[i];
|
||||
UINT format = GetFormat(flavorStr.get());
|
||||
|
||||
auto dataOrError =
|
||||
GetDataFromDataObject(aDataObject, anIndex, aWindow, flavorStr);
|
||||
if (dataOrError.isErr() || !dataOrError.inspect()) {
|
||||
continue;
|
||||
// Try to get the data using the desired flavor. This might fail, but all is
|
||||
// not lost.
|
||||
void* data = nullptr;
|
||||
uint32_t dataLen = 0;
|
||||
bool dataFound = false;
|
||||
if (nullptr != aDataObject) {
|
||||
if (NS_SUCCEEDED(GetNativeDataOffClipboard(aDataObject, anIndex, format,
|
||||
flavorStr.get(), &data,
|
||||
&dataLen))) {
|
||||
dataFound = true;
|
||||
}
|
||||
} else if (nullptr != aWindow) {
|
||||
if (NS_SUCCEEDED(GetNativeDataOffClipboard(aWindow, anIndex, format,
|
||||
&data, &dataLen))) {
|
||||
dataFound = true;
|
||||
}
|
||||
}
|
||||
|
||||
NS_ASSERTION(dataOrError.inspect(),
|
||||
"About to put null data into the transferable");
|
||||
aTransferable->SetTransferData(flavorStr.get(), dataOrError.inspect());
|
||||
// we found one, get out of the loop
|
||||
break;
|
||||
// This is our second chance to try to find some data, having not found it
|
||||
// when directly asking for the flavor. Let's try digging around in other
|
||||
// flavors to help satisfy our craving for data.
|
||||
if (!dataFound) {
|
||||
if (flavorStr.EqualsLiteral(kTextMime)) {
|
||||
dataFound =
|
||||
FindUnicodeFromPlainText(aDataObject, anIndex, &data, &dataLen);
|
||||
} else if (flavorStr.EqualsLiteral(kURLMime)) {
|
||||
// drags from other windows apps expose the native
|
||||
// CFSTR_INETURL{A,W} flavor
|
||||
dataFound = FindURLFromNativeURL(aDataObject, anIndex, &data, &dataLen);
|
||||
if (!dataFound) {
|
||||
dataFound =
|
||||
FindURLFromLocalFile(aDataObject, anIndex, &data, &dataLen);
|
||||
}
|
||||
} else {
|
||||
mozilla::Maybe<UINT> secondaryFormat =
|
||||
GetSecondaryFormat(flavorStr.get());
|
||||
if (secondaryFormat) {
|
||||
// Fall back to secondary format
|
||||
dataFound = NS_SUCCEEDED(GetNativeDataOffClipboard(
|
||||
aDataObject, anIndex, secondaryFormat.value(), flavorStr.get(),
|
||||
&data, &dataLen));
|
||||
}
|
||||
}
|
||||
} // if we try one last ditch effort to find our data
|
||||
|
||||
// Hopefully by this point we've found it and can go about our business
|
||||
if (dataFound) {
|
||||
nsCOMPtr<nsISupports> genericDataWrapper;
|
||||
if (flavorStr.EqualsLiteral(kFileMime)) {
|
||||
// we have a file path in |data|. Create an nsLocalFile object.
|
||||
nsDependentString filepath(reinterpret_cast<char16_t*>(data));
|
||||
nsCOMPtr<nsIFile> file;
|
||||
if (NS_SUCCEEDED(NS_NewLocalFile(filepath, getter_AddRefs(file)))) {
|
||||
genericDataWrapper = do_QueryInterface(file);
|
||||
}
|
||||
free(data);
|
||||
} else if (flavorStr.EqualsLiteral(kNativeHTMLMime)) {
|
||||
uint32_t dummy;
|
||||
// the editor folks want CF_HTML exactly as it's on the clipboard, no
|
||||
// conversions, no fancy stuff. Pull it off the clipboard, stuff it into
|
||||
// a wrapper and hand it back to them.
|
||||
if (FindPlatformHTML(aDataObject, anIndex, &data, &dummy, &dataLen)) {
|
||||
nsPrimitiveHelpers::CreatePrimitiveForData(
|
||||
flavorStr, data, dataLen, getter_AddRefs(genericDataWrapper));
|
||||
} else {
|
||||
free(data);
|
||||
continue; // something wrong with this flavor, keep looking for other
|
||||
// data
|
||||
}
|
||||
free(data);
|
||||
} else if (flavorStr.EqualsLiteral(kHTMLMime)) {
|
||||
uint32_t startOfData = 0;
|
||||
// The JS folks want CF_HTML exactly as it is on the clipboard, but
|
||||
// minus the CF_HTML header index information.
|
||||
// It also needs to be converted to UTF16 and have linebreaks changed.
|
||||
if (FindPlatformHTML(aDataObject, anIndex, &data, &startOfData,
|
||||
&dataLen)) {
|
||||
dataLen -= startOfData;
|
||||
nsPrimitiveHelpers::CreatePrimitiveForCFHTML(
|
||||
static_cast<char*>(data) + startOfData, &dataLen,
|
||||
getter_AddRefs(genericDataWrapper));
|
||||
} else {
|
||||
free(data);
|
||||
continue; // something wrong with this flavor, keep looking for other
|
||||
// data
|
||||
}
|
||||
free(data);
|
||||
} else if (flavorStr.EqualsLiteral(kJPEGImageMime) ||
|
||||
flavorStr.EqualsLiteral(kJPGImageMime) ||
|
||||
flavorStr.EqualsLiteral(kPNGImageMime)) {
|
||||
nsIInputStream* imageStream = reinterpret_cast<nsIInputStream*>(data);
|
||||
genericDataWrapper = do_QueryInterface(imageStream);
|
||||
NS_IF_RELEASE(imageStream);
|
||||
} else {
|
||||
// Treat custom types as a string of bytes.
|
||||
if (!flavorStr.EqualsLiteral(kCustomTypesMime)) {
|
||||
bool isRTF = flavorStr.EqualsLiteral(kRTFMime);
|
||||
// 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(isRTF, &data,
|
||||
&signedLen);
|
||||
dataLen = signedLen;
|
||||
|
||||
if (isRTF) {
|
||||
// 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.get(), genericDataWrapper);
|
||||
res = NS_OK;
|
||||
|
||||
// we found one, get out of the loop
|
||||
break;
|
||||
}
|
||||
} // foreach flavor
|
||||
|
||||
return NS_OK;
|
||||
return res;
|
||||
}
|
||||
|
||||
//
|
||||
@@ -1384,24 +1382,24 @@ bool nsClipboard ::IsInternetShortcut(const nsAString& inFileName) {
|
||||
} // IsInternetShortcut
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
mozilla::Result<nsCOMPtr<nsISupports>, nsresult>
|
||||
nsClipboard::GetNativeClipboardData(const nsACString& aFlavor,
|
||||
NS_IMETHODIMP
|
||||
nsClipboard::GetNativeClipboardData(nsITransferable* aTransferable,
|
||||
ClipboardType aWhichClipboard) {
|
||||
MOZ_DIAGNOSTIC_ASSERT(aTransferable);
|
||||
MOZ_DIAGNOSTIC_ASSERT(
|
||||
nsIClipboard::IsClipboardTypeSupported(aWhichClipboard));
|
||||
|
||||
MOZ_CLIPBOARD_LOG("%s aWhichClipboard=%i", __FUNCTION__, aWhichClipboard);
|
||||
|
||||
nsresult res;
|
||||
// This makes sure we can use the OLE functionality for the clipboard
|
||||
IDataObject* dataObj;
|
||||
if (S_OK == RepeatedlyTryOleGetClipboard(&dataObj)) {
|
||||
auto dataObjRelease = mozilla::MakeScopeExit([&] { dataObj->Release(); });
|
||||
// Use OLE IDataObject for clipboard operations
|
||||
MOZ_CLIPBOARD_LOG(" use OLE IDataObject:");
|
||||
if (MOZ_CLIPBOARD_LOG_ENABLED()) {
|
||||
IEnumFORMATETC* pEnum = nullptr;
|
||||
if (S_OK == dataObj->EnumFormatEtc(DATADIR_GET, &pEnum)) {
|
||||
auto pEnumRelease = mozilla::MakeScopeExit([&] { pEnum->Release(); });
|
||||
FORMATETC fEtc;
|
||||
while (S_OK == pEnum->Next(1, &fEtc, nullptr)) {
|
||||
nsAutoString format;
|
||||
@@ -1411,13 +1409,16 @@ nsClipboard::GetNativeClipboardData(const nsACString& aFlavor,
|
||||
NS_ConvertUTF16toUTF8(format).get());
|
||||
}
|
||||
}
|
||||
pEnum->Release();
|
||||
}
|
||||
|
||||
return GetDataFromDataObject(dataObj, 0, nullptr, PromiseFlatCString(aFlavor));
|
||||
res = GetDataFromDataObject(dataObj, 0, nullptr, aTransferable);
|
||||
dataObj->Release();
|
||||
} else {
|
||||
// do it the old manual way
|
||||
res = GetDataFromDataObject(nullptr, 0, mWindow, aTransferable);
|
||||
}
|
||||
|
||||
// do it the old manual way
|
||||
return GetDataFromDataObject(nullptr, 0, mWindow, PromiseFlatCString(aFlavor));
|
||||
return res;
|
||||
}
|
||||
|
||||
nsresult nsClipboard::EmptyNativeClipboardData(ClipboardType aWhichClipboard) {
|
||||
|
||||
@@ -22,7 +22,7 @@ struct IDataObject;
|
||||
* Native Win32 Clipboard wrapper
|
||||
*/
|
||||
|
||||
class nsClipboard final : public nsBaseClipboard, public nsIObserver {
|
||||
class nsClipboard : public nsBaseClipboard, public nsIObserver {
|
||||
virtual ~nsClipboard();
|
||||
|
||||
public:
|
||||
@@ -41,9 +41,6 @@ class nsClipboard final : public nsBaseClipboard, public nsIObserver {
|
||||
static nsresult SetupNativeDataObject(nsITransferable* aTransferable,
|
||||
IDataObject* aDataObj,
|
||||
MightNeedToFlush* = nullptr);
|
||||
static mozilla::Result<nsCOMPtr<nsISupports>, nsresult> GetDataFromDataObject(
|
||||
IDataObject* aDataObject, UINT anIndex, nsIWidget* aWindow,
|
||||
const nsCString& aFlavor);
|
||||
static nsresult GetDataFromDataObject(IDataObject* aDataObject, UINT anIndex,
|
||||
nsIWidget* aWindow,
|
||||
nsITransferable* aTransferable);
|
||||
@@ -81,8 +78,8 @@ class nsClipboard final : public nsBaseClipboard, public nsIObserver {
|
||||
// Implement the native clipboard behavior.
|
||||
NS_IMETHOD SetNativeClipboardData(nsITransferable* aTransferable,
|
||||
ClipboardType aWhichClipboard) override;
|
||||
mozilla::Result<nsCOMPtr<nsISupports>, nsresult> GetNativeClipboardData(
|
||||
const nsACString& aFlavor, ClipboardType aWhichClipboard) override;
|
||||
NS_IMETHOD GetNativeClipboardData(nsITransferable* aTransferable,
|
||||
ClipboardType aWhichClipboard) override;
|
||||
nsresult EmptyNativeClipboardData(ClipboardType aWhichClipboard) override;
|
||||
mozilla::Result<bool, nsresult> HasNativeClipboardDataMatchingFlavors(
|
||||
const nsTArray<nsCString>& aFlavorList,
|
||||
|
||||
Reference in New Issue
Block a user