diff --git a/widget/windows/nsClipboard.cpp b/widget/windows/nsClipboard.cpp index 67cdee82ea8..a98f384ba82 100644 --- a/widget/windows/nsClipboard.cpp +++ b/widget/windows/nsClipboard.cpp @@ -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(*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(tempOutData), tempDataLen, esc_OnlyNonASCII | esc_SkipControl, urlUnescapedA); + + nsString urlString; + if (unescaped) + NS_CopyNativeToUnicode(urlUnescapedA, urlString); + else + NS_CopyNativeToUnicode(nsDependentCString(static_cast(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(*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; diff --git a/widget/windows/nsDataObj.cpp b/widget/windows/nsDataObj.cpp index fcdae453df2..f62da18eb05 100644 --- a/widget/windows/nsDataObj.cpp +++ b/widget/windows/nsDataObj.cpp @@ -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(moz_xmalloc(bufferSize)); + char16_t* castedUnicode = reinterpret_cast(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(data) );