зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1497580 - Save text/html as UTF-8 to the clipboard. r=karlt
I verified that we can still copy from Firefox to an older version of Firefox without this patch. LibreOffice also still works. Talking to some GTK people on IRC they are also happy about UTF-8 instead of wrongly declared UCS2. Differential Revision: https://phabricator.services.mozilla.com/D8467 --HG-- extra : moz-landing-system : lando
This commit is contained in:
Родитель
fe2a8105db
Коммит
90b0f3e9cb
|
@ -34,12 +34,16 @@
|
||||||
|
|
||||||
#include "mozilla/Encoding.h"
|
#include "mozilla/Encoding.h"
|
||||||
|
|
||||||
|
|
||||||
using namespace mozilla;
|
using namespace mozilla;
|
||||||
|
|
||||||
// Idle timeout for receiving selection and property notify events (microsec)
|
// Idle timeout for receiving selection and property notify events (microsec)
|
||||||
const int kClipboardTimeout = 500000;
|
const int kClipboardTimeout = 500000;
|
||||||
|
|
||||||
|
// We add this prefix to HTML markup, so that GetHTMLCharset can correctly
|
||||||
|
// detect the HTML as UTF-8 encoded.
|
||||||
|
static const char kHTMLMarkupPrefix[] =
|
||||||
|
R"(<meta http-equiv="content-type" content="text/html; charset=utf-8">)";
|
||||||
|
|
||||||
// Callback when someone asks us for the data
|
// Callback when someone asks us for the data
|
||||||
void
|
void
|
||||||
clipboard_get_cb(GtkClipboard *aGtkClipboard,
|
clipboard_get_cb(GtkClipboard *aGtkClipboard,
|
||||||
|
@ -527,6 +531,31 @@ nsClipboard::SelectionGetEvent(GtkClipboard *aClipboard,
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (selectionTarget == gdk_atom_intern(kHTMLMime, FALSE)) {
|
||||||
|
rv = trans->GetTransferData(kHTMLMime, getter_AddRefs(item), &len);
|
||||||
|
if (!item || NS_FAILED(rv)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
nsCOMPtr<nsISupportsString> wideString;
|
||||||
|
wideString = do_QueryInterface(item);
|
||||||
|
if (!wideString) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
nsAutoString ucs2string;
|
||||||
|
wideString->GetData(ucs2string);
|
||||||
|
|
||||||
|
nsAutoCString html;
|
||||||
|
// Add the prefix so the encoding is correctly detected.
|
||||||
|
html.AppendLiteral(kHTMLMarkupPrefix);
|
||||||
|
AppendUTF16toUTF8(ucs2string, html);
|
||||||
|
|
||||||
|
gtk_selection_data_set(aSelectionData, selectionTarget, 8,
|
||||||
|
(const guchar*)html.get(), html.Length());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Try to match up the selection data target to something our
|
// Try to match up the selection data target to something our
|
||||||
// transferable provides.
|
// transferable provides.
|
||||||
gchar *target_name = gdk_atom_name(selectionTarget);
|
gchar *target_name = gdk_atom_name(selectionTarget);
|
||||||
|
@ -545,31 +574,10 @@ nsClipboard::SelectionGetEvent(GtkClipboard *aClipboard,
|
||||||
item, &primitive_data, len);
|
item, &primitive_data, len);
|
||||||
|
|
||||||
if (primitive_data) {
|
if (primitive_data) {
|
||||||
// Check to see if the selection data is text/html
|
|
||||||
if (selectionTarget == gdk_atom_intern (kHTMLMime, FALSE)) {
|
|
||||||
/*
|
|
||||||
* "text/html" can be encoded UCS2. It is recommended that
|
|
||||||
* documents transmitted as UCS2 always begin with a ZERO-WIDTH
|
|
||||||
* NON-BREAKING SPACE character (hexadecimal FEFF, also called
|
|
||||||
* Byte Order Mark (BOM)). Adding BOM can help other app to
|
|
||||||
* detect mozilla use UCS2 encoding when copy-paste.
|
|
||||||
*/
|
|
||||||
guchar *buffer = (guchar *)
|
|
||||||
g_malloc((len * sizeof(guchar)) + sizeof(char16_t));
|
|
||||||
if (!buffer)
|
|
||||||
return;
|
|
||||||
char16_t prefix = 0xFEFF;
|
|
||||||
memcpy(buffer, &prefix, sizeof(prefix));
|
|
||||||
memcpy(buffer + sizeof(prefix), primitive_data, len);
|
|
||||||
g_free((guchar *)primitive_data);
|
|
||||||
primitive_data = (guchar *)buffer;
|
|
||||||
len += sizeof(prefix);
|
|
||||||
}
|
|
||||||
|
|
||||||
gtk_selection_data_set(aSelectionData, selectionTarget,
|
gtk_selection_data_set(aSelectionData, selectionTarget,
|
||||||
8, /* 8 bits in a unit */
|
8, /* 8 bits in a unit */
|
||||||
(const guchar *)primitive_data, len);
|
(const guchar *)primitive_data, len);
|
||||||
g_free(primitive_data);
|
free(primitive_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
g_free(target_name);
|
g_free(target_name);
|
||||||
|
@ -656,8 +664,19 @@ void ConvertHTMLtoUCS2(const char* data, int32_t dataLength,
|
||||||
outUnicodeLen = 0;
|
outUnicodeLen = 0;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto dataSpan = MakeSpan(data, dataLength);
|
||||||
|
// Remove kHTMLMarkupPrefix again, it won't necessarily cause any
|
||||||
|
// issues, but might confuse other users.
|
||||||
|
const size_t prefixLen = ArrayLength(kHTMLMarkupPrefix) - 1;
|
||||||
|
if (dataSpan.Length() >= prefixLen &&
|
||||||
|
Substring(data, prefixLen).EqualsLiteral(kHTMLMarkupPrefix)) {
|
||||||
|
dataSpan = dataSpan.From(prefixLen);
|
||||||
|
}
|
||||||
|
|
||||||
auto decoder = encoding->NewDecoder();
|
auto decoder = encoding->NewDecoder();
|
||||||
CheckedInt<size_t> needed = decoder->MaxUTF16BufferLength(dataLength);
|
CheckedInt<size_t> needed =
|
||||||
|
decoder->MaxUTF16BufferLength(dataSpan.Length());
|
||||||
if (!needed.isValid() || needed.value() > INT32_MAX) {
|
if (!needed.isValid() || needed.value() > INT32_MAX) {
|
||||||
outUnicodeLen = 0;
|
outUnicodeLen = 0;
|
||||||
return;
|
return;
|
||||||
|
@ -672,17 +691,13 @@ void ConvertHTMLtoUCS2(const char* data, int32_t dataLength,
|
||||||
size_t written;
|
size_t written;
|
||||||
bool hadErrors;
|
bool hadErrors;
|
||||||
Tie(result, read, written, hadErrors) =
|
Tie(result, read, written, hadErrors) =
|
||||||
decoder->DecodeToUTF16(AsBytes(MakeSpan(data, dataLength)),
|
decoder->DecodeToUTF16(AsBytes(dataSpan),
|
||||||
MakeSpan(*unicodeData, needed.value()),
|
MakeSpan(*unicodeData, needed.value()),
|
||||||
true);
|
true);
|
||||||
MOZ_ASSERT(result == kInputEmpty);
|
MOZ_ASSERT(result == kInputEmpty);
|
||||||
MOZ_ASSERT(read == size_t(dataLength));
|
MOZ_ASSERT(read == size_t(dataSpan.Length()));
|
||||||
MOZ_ASSERT(written <= needed.value());
|
MOZ_ASSERT(written <= needed.value());
|
||||||
Unused << hadErrors;
|
Unused << hadErrors;
|
||||||
#ifdef DEBUG_CLIPBOARD
|
|
||||||
if (read != dataLength)
|
|
||||||
printf("didn't consume all the bytes\n");
|
|
||||||
#endif
|
|
||||||
outUnicodeLen = written;
|
outUnicodeLen = written;
|
||||||
// null terminate.
|
// null terminate.
|
||||||
(*unicodeData)[outUnicodeLen] = '\0';
|
(*unicodeData)[outUnicodeLen] = '\0';
|
||||||
|
@ -706,7 +721,7 @@ void GetHTMLCharset(const char* data, int32_t dataLength, nsCString& str)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// no "FFFE" and "FEFF", assume ASCII first to find "charset" info
|
// no "FFFE" and "FEFF", assume ASCII first to find "charset" info
|
||||||
const nsDependentCString htmlStr(data, dataLength);
|
const nsDependentCSubstring htmlStr(data, dataLength);
|
||||||
nsACString::const_iterator start, end;
|
nsACString::const_iterator start, end;
|
||||||
htmlStr.BeginReading(start);
|
htmlStr.BeginReading(start);
|
||||||
htmlStr.EndReading(end);
|
htmlStr.EndReading(end);
|
||||||
|
|
Загрузка…
Ссылка в новой задаче