Bug 1243507 - Reimplement non-Unicode clipboard formats as bug 943294 broke drag and drop between some Unicode-unaware apps. r=jimm

This commit is contained in:
Masatoshi Kimura 2016-02-04 04:13:13 +09:00
parent d2142aaa0b
commit 2b932ae233
2 changed files with 107 additions and 7 deletions

View File

@ -92,8 +92,9 @@ UINT nsClipboard::GetFormat(const char* aMimeStr)
{
UINT format;
if (strcmp(aMimeStr, kTextMime) == 0 ||
strcmp(aMimeStr, kUnicodeMime) == 0)
if (strcmp(aMimeStr, kTextMime) == 0)
format = CF_TEXT;
else if (strcmp(aMimeStr, kUnicodeMime) == 0)
format = CF_UNICODETEXT;
else if (strcmp(aMimeStr, kRTFMime) == 0)
format = ::RegisterClipboardFormat(L"Rich Text Format");
@ -179,7 +180,14 @@ nsresult nsClipboard::SetupNativeDataObject(nsITransferable * aTransferable, IDa
// Do various things internal to the implementation, like map one
// flavor to another or add additional flavors based on what's required
// for the win32 impl.
if ( strcmp(flavorStr, kHTMLMime) == 0 ) {
if ( strcmp(flavorStr, kUnicodeMime) == 0 ) {
// if we find text/unicode, also advertise text/plain (which we will convert
// on our own in nsDataObj::GetText().
FORMATETC textFE;
SET_FORMATETC(textFE, CF_TEXT, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL);
dObj->AddDataFlavor(kTextMime, &textFE);
}
else if ( strcmp(flavorStr, kHTMLMime) == 0 ) {
// if we find text/html, also advertise win32's html flavor (which we will convert
// on our own in nsDataObj::GetText().
FORMATETC htmlFE;
@ -191,10 +199,14 @@ nsresult nsClipboard::SetupNativeDataObject(nsITransferable * aTransferable, IDa
// the "file" flavors so that the win32 shell knows to create an internet
// shortcut when it sees one of these beasts.
FORMATETC shortcutFE;
SET_FORMATETC(shortcutFE, ::RegisterClipboardFormat(CFSTR_FILEDESCRIPTORA), 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL)
dObj->AddDataFlavor(kURLMime, &shortcutFE);
SET_FORMATETC(shortcutFE, ::RegisterClipboardFormat(CFSTR_FILEDESCRIPTORW), 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL)
dObj->AddDataFlavor(kURLMime, &shortcutFE);
SET_FORMATETC(shortcutFE, ::RegisterClipboardFormat(CFSTR_FILECONTENTS), 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL)
dObj->AddDataFlavor(kURLMime, &shortcutFE);
SET_FORMATETC(shortcutFE, ::RegisterClipboardFormat(CFSTR_INETURLA), 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL)
dObj->AddDataFlavor(kURLMime, &shortcutFE);
SET_FORMATETC(shortcutFE, ::RegisterClipboardFormat(CFSTR_INETURLW), 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL)
dObj->AddDataFlavor(kURLMime, &shortcutFE);
}
@ -607,9 +619,11 @@ nsresult nsClipboard::GetDataFromDataObject(IDataObject * aDataObject,
// when directly asking for the flavor. Let's try digging around in other
// flavors to help satisfy our craving for data.
if ( !dataFound ) {
if ( strcmp(flavorStr, kURLMime) == 0 ) {
if ( strcmp(flavorStr, kUnicodeMime) == 0 )
dataFound = FindUnicodeFromPlainText ( aDataObject, anIndex, &data, &dataLen );
else if ( strcmp(flavorStr, kURLMime) == 0 ) {
// drags from other windows apps expose the native
// CFSTR_INETURLW flavor
// CFSTR_INETURL{A,W} flavor
dataFound = FindURLFromNativeURL ( aDataObject, anIndex, &data, &dataLen );
if ( !dataFound )
dataFound = FindURLFromLocalFile ( aDataObject, anIndex, &data, &dataLen );
@ -759,6 +773,39 @@ nsClipboard :: FindPlatformHTML ( IDataObject* inDataObject, UINT inIndex,
}
//
// FindUnicodeFromPlainText
//
// we are looking for text/unicode and we failed to find it on the clipboard first,
// try again with text/plain. If that is present, convert it to unicode.
//
bool
nsClipboard :: FindUnicodeFromPlainText ( IDataObject* inDataObject, UINT inIndex, void** outData, uint32_t* outDataLen )
{
// we are looking for text/unicode and we failed to find it on the clipboard first,
// try again with text/plain. If that is present, convert it to unicode.
nsresult rv = GetNativeDataOffClipboard(inDataObject, inIndex, GetFormat(kTextMime), nullptr, outData, outDataLen);
if (NS_FAILED(rv) || !*outData) {
return false;
}
const char* castedText = static_cast<char*>(*outData);
nsAutoString tmp;
rv = NS_CopyNativeToUnicode(nsDependentCSubstring(castedText, *outDataLen), tmp);
if (NS_FAILED(rv)) {
return false;
}
// out with the old, in with the new
free(*outData);
*outData = ToNewUnicode(tmp);
*outDataLen = tmp.Length() * sizeof(char16_t);
return true;
} // FindUnicodeFromPlainText
//
// FindURLFromLocalFile
//
@ -825,7 +872,7 @@ nsClipboard :: FindURLFromLocalFile ( IDataObject* inDataObject, UINT inIndex, v
//
// we are looking for a URL and couldn't find it using our internal
// URL flavor, so look for it using the native URL flavor,
// CF_INETURLSTRW
// CF_INETURLSTRW (We don't handle CF_INETURLSTRA currently)
//
bool
nsClipboard :: FindURLFromNativeURL ( IDataObject* inDataObject, UINT inIndex, void** outData, uint32_t* outDataLen )
@ -846,6 +893,29 @@ nsClipboard :: FindURLFromNativeURL ( IDataObject* inDataObject, UINT inIndex, v
free(tempOutData);
dataFound = true;
}
else {
loadResult = GetNativeDataOffClipboard(inDataObject, inIndex, ::RegisterClipboardFormat(CFSTR_INETURLA), nullptr, &tempOutData, &tempDataLen);
if ( NS_SUCCEEDED(loadResult) && tempOutData ) {
// CFSTR_INETURLA is (currently) equal to CFSTR_SHELLURL which is equal to CF_TEXT
// which is by definition ANSI encoded.
nsCString urlUnescapedA;
bool unescaped = NS_UnescapeURL(static_cast<char*>(tempOutData), tempDataLen, esc_OnlyNonASCII | esc_SkipControl, urlUnescapedA);
nsString urlString;
if (unescaped)
NS_CopyNativeToUnicode(urlUnescapedA, urlString);
else
NS_CopyNativeToUnicode(nsDependentCString(static_cast<char*>(tempOutData), tempDataLen), urlString);
// the internal mozilla URL format, text/x-moz-url, contains
// URL\ntitle. Since we don't actually have a title here,
// just repeat the URL to fake it.
*outData = ToNewUnicode(urlString + NS_LITERAL_STRING("\n") + urlString);
*outDataLen = NS_strlen(static_cast<char16_t*>(*outData)) * sizeof(char16_t);
free(tempOutData);
dataFound = true;
}
}
return dataFound;
} // FindURLFromNativeURL
@ -942,6 +1012,16 @@ NS_IMETHODIMP nsClipboard::HasDataMatchingFlavors(const char** aFlavorList,
*_retval = true;
break;
}
else {
// We haven't found the exact flavor the client asked for, but maybe we can
// still find it from something else that's on the clipboard...
if (strcmp(aFlavorList[i], kUnicodeMime) == 0) {
// client asked for unicode and it wasn't present, check if we have CF_TEXT.
// We'll handle the actual data substitution in the data object.
if (IsClipboardFormatAvailable(GetFormat(kTextMime)))
*_retval = true;
}
}
}
return NS_OK;

View File

@ -1290,7 +1290,27 @@ HRESULT nsDataObj::GetText(const nsACString & aDataFlavor, FORMATETC& aFE, STGME
// by the appropriate size to account for the null (one char for CF_TEXT, one char16_t for
// CF_UNICODETEXT).
DWORD allocLen = (DWORD)len;
if ( aFE.cfFormat == nsClipboard::CF_HTML ) {
if ( aFE.cfFormat == CF_TEXT ) {
// Someone is asking for text/plain; convert the unicode (assuming it's present)
// to text with the correct platform encoding.
size_t bufferSize = sizeof(char)*(len + 2);
char* plainTextData = static_cast<char*>(moz_xmalloc(bufferSize));
char16_t* castedUnicode = reinterpret_cast<char16_t*>(data);
int32_t plainTextLen = WideCharToMultiByte(CP_ACP, 0, (LPCWSTR)castedUnicode, len / 2 + 1, plainTextData, bufferSize, NULL, NULL);
// replace the unicode data with our plaintext data. Recall that |plainTextLen| doesn't include
// the null in the length.
free(data);
if ( plainTextLen ) {
data = plainTextData;
allocLen = plainTextLen;
}
else {
free(plainTextData);
NS_WARNING ( "Oh no, couldn't convert unicode to plain text" );
return S_OK;
}
}
else if ( aFE.cfFormat == nsClipboard::CF_HTML ) {
// Someone is asking for win32's HTML flavor. Convert our html fragment
// from unicode to UTF-8 then put it into a format specified by msft.
NS_ConvertUTF16toUTF8 converter ( reinterpret_cast<char16_t*>(data) );