diff --git a/widget/gtk/nsClipboard.cpp b/widget/gtk/nsClipboard.cpp index 75ad319a1ece..48160b39a454 100644 --- a/widget/gtk/nsClipboard.cpp +++ b/widget/gtk/nsClipboard.cpp @@ -253,6 +253,76 @@ void nsClipboard::SetTransferableData(nsITransferable* aTransferable, aTransferable->SetTransferData(aFlavor.get(), wrapper); } +static bool IsMIMEAtFlavourList(const nsTArray& 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::FilterImportedFlavors(int32_t aWhichClipboard, + nsTArray& aFlavors) { + LOGCLIP(("nsClipboard::FilterImportedFlavors")); + + int targetNums; + GdkAtom* targets = mContext->GetTargets(aWhichClipboard, &targetNums); + if (!targets) { + LOGCLIP((" X11: no targes at clipboard (null), quit.\n")); + return false; + } + + for (int i = 0; i < targetNums; i++) { + gchar* atom_name = gdk_atom_name(targets[i]); + if (!atom_name) { + continue; + } + // Filter out system MIME types. + if (strcmp(atom_name, "TARGETS") == 0 || + strcmp(atom_name, "TIMESTAMP") == 0 || + strcmp(atom_name, "SAVE_TARGETS") == 0 || + strcmp(atom_name, "MULTIPLE") == 0) { + continue; + } + // Filter out types which can't be converted to text. + if (strncmp(atom_name, "image/", 6) == 0 || + strncmp(atom_name, "application/", 12) == 0 || + strncmp(atom_name, "audio/", 6) == 0 || + strncmp(atom_name, "video/", 6) == 0) { + continue; + } + // We have some other MIME type on clipboard which can be hopefully + // converted to text without any problem. + LOGCLIP((" X11: text types in clipboard, no need to filter them.\n")); + return true; + } + + // So make sure we offer only types we have at clipboard. + nsTArray clipboardFlavors; + for (int i = 0; i < targetNums; i++) { + gchar* atom_name = gdk_atom_name(targets[i]); + if (!atom_name) { + continue; + } + if (IsMIMEAtFlavourList(aFlavors, atom_name)) { + clipboardFlavors.AppendElement(nsCString(atom_name)); + } + } + aFlavors.SwapElements(clipboardFlavors); +#ifdef MOZ_LOGGING + LOGCLIP((" X11: Flavors which match clipboard content:\n")); + for (uint32_t i = 0; i < aFlavors.Length(); i++) { + LOGCLIP((" %s\n", aFlavors[i].get())); + } +#endif + return true; +} + NS_IMETHODIMP nsClipboard::GetData(nsITransferable* aTransferable, int32_t aWhichClipboard) { LOGCLIP(("nsClipboard::GetData (%s)\n", @@ -270,7 +340,6 @@ nsClipboard::GetData(nsITransferable* aTransferable, int32_t aWhichClipboard) { LOGCLIP((" FlavorsTransferableCanImport falied!\n")); return rv; } - #ifdef MOZ_LOGGING LOGCLIP(("Flavors which can be imported:\n")); for (uint32_t i = 0; i < flavors.Length(); i++) { @@ -278,6 +347,14 @@ nsClipboard::GetData(nsITransferable* aTransferable, int32_t aWhichClipboard) { } #endif + // Filter out MIME types on X11 to prevent unwanted conversions, + // see Bug 1611407 + if (widget::GdkIsX11Display()) { + if (!FilterImportedFlavors(aWhichClipboard, flavors)) { + return NS_OK; + } + } + for (uint32_t i = 0; i < flavors.Length(); i++) { nsCString& flavorStr = flavors[i]; diff --git a/widget/gtk/nsClipboard.h b/widget/gtk/nsClipboard.h index 193020b0c5f4..6c42ac81caa5 100644 --- a/widget/gtk/nsClipboard.h +++ b/widget/gtk/nsClipboard.h @@ -80,6 +80,9 @@ class nsClipboard : public nsIClipboard, public nsIObserver { void ClearTransferable(int32_t aWhichClipboard); + bool FilterImportedFlavors(int32_t aWhichClipboard, + nsTArray& aFlavors); + // Hang on to our owners and transferables so we can transfer data // when asked. nsCOMPtr mSelectionOwner; diff --git a/widget/gtk/nsClipboardX11.cpp b/widget/gtk/nsClipboardX11.cpp index bf05cc30537b..e1def2518169 100644 --- a/widget/gtk/nsClipboardX11.cpp +++ b/widget/gtk/nsClipboardX11.cpp @@ -204,9 +204,11 @@ void nsRetrievalContextX11::Complete(ClipboardDataType aDataType, gint dataLength = gtk_selection_data_get_length(selection); const guchar* data = gtk_selection_data_get_data(selection); - - LOGCLIP((" got data %p len %d\n", data, dataLength)); - +#ifdef MOZ_LOGGING + GdkAtom target = gtk_selection_data_get_target(selection); + LOGCLIP((" got data %p len %d MIME %s\n", data, dataLength, + gdk_atom_name(target))); +#endif if (dataLength > 0) { mClipboardDataLength = dataLength; mClipboardData = moz_xmalloc(dataLength); @@ -266,14 +268,17 @@ bool nsRetrievalContextX11::WaitForClipboardData(ClipboardDataType aDataType, switch (aDataType) { case CLIPBOARD_DATA: + LOGCLIP((" getting DATA MIME %s\n", aMimeType)); gtk_clipboard_request_contents(clipboard, gdk_atom_intern(aMimeType, FALSE), clipboard_contents_received, handler); break; case CLIPBOARD_TEXT: + LOGCLIP((" getting TEXT\n")); gtk_clipboard_request_text(clipboard, clipboard_text_received, handler); break; case CLIPBOARD_TARGETS: + LOGCLIP((" getting TARGETS\n")); gtk_clipboard_request_contents(clipboard, mTargetMIMEType, clipboard_contents_received, handler); break;