2010-05-31 Martin Robinson <mrobinson@igalia.com>
authormrobinson@webkit.org <mrobinson@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 31 May 2010 17:31:00 +0000 (17:31 +0000)
committermrobinson@webkit.org <mrobinson@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 31 May 2010 17:31:00 +0000 (17:31 +0000)
        Reviewed by Gustavo Noronha Silva.

        [GTK] Text copied from a WebView cannot be pasted into gnome-terminal
        https://bugs.webkit.org/show_bug.cgi?id=39827

        Switch all methods in Pasteboard to use the PasteboardHelper + DataObjectGtk
        approach used in other parts of WebKit GTK+.

        * platform/gtk/PasteboardGtk.cpp:
        (WebCore::Pasteboard::writeSelection): Switch to using PasteboardHelper.
        (WebCore::Pasteboard::writePlainText): Ditto.
        (WebCore::Pasteboard::writeURL): Ditto.
        (WebCore::Pasteboard::writeImage): Ditto.
        (WebCore::Pasteboard::clear): Small cleanup.
        (WebCore::Pasteboard::documentFragment): Switch to using PasteboardHelper.
        (WebCore::Pasteboard::plainText): Ditto.
2010-05-31  Martin Robinson  <mrobinson@igalia.com>

        Reviewed by Gustavo Noronha Silva.

        [GTK] Text copied from a WebView cannot be pasted into gnome-terminal
        https://bugs.webkit.org/show_bug.cgi?id=39827

        Add a test to prevent regressions for this issue.

        * tests/testcopyandpaste.c: Added.
        (test_info_new):
        (test_info_destroy):
        (copy_and_paste_fixture_setup):
        (copy_and_paste_fixture_teardown):
        (load_status_cb):
        (map_event_cb):
        (test_copy_and_paste):
        (main):

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@60447 268f45cc-cd09-0410-ab3c-d52691b4dbfc

GNUmakefile.am
WebCore/ChangeLog
WebCore/platform/gtk/PasteboardGtk.cpp
WebKit/gtk/ChangeLog
WebKit/gtk/tests/testcopyandpaste.c [new file with mode: 0644]

index d6dc045..bb96036 100644 (file)
@@ -662,7 +662,8 @@ TEST_PROGS += \
        Programs/unittests/testwebresource \
        Programs/unittests/testwebdatasource \
        Programs/unittests/testwebview \
-       Programs/unittests/testkeyevents
+       Programs/unittests/testkeyevents \
+       Programs/unittests/testcopyandpaste
 
 # Add additional tests here
 Programs_unittests_testdomdocument_SOURCES = WebKit/gtk/tests/testdomdocument.c
@@ -767,6 +768,11 @@ Programs_unittests_testkeyevents_CFLAGS = $(webkit_tests_cflags)
 Programs_unittests_testkeyevents_LDADD = $(webkit_tests_ldadd)
 Programs_unittests_testkeyevents_LDFLAGS = $(webkit_tests_ldflags)
 
+Programs_unittests_testcopyandpaste_SOURCES = WebKit/gtk/tests/testcopyandpaste.c
+Programs_unittests_testcopyandpaste_CFLAGS = $(webkit_tests_cflags)
+Programs_unittests_testcopyandpaste_LDADD = $(webkit_tests_ldadd)
+Programs_unittests_testcopyandpaste_LDFLAGS = $(webkit_tests_ldflags)
+
 # Autogenerated sources
 BUILT_SOURCES += \
        $(javascriptcore_built_sources) \
index 018b451..ca3e06d 100644 (file)
@@ -1,3 +1,22 @@
+2010-05-31  Martin Robinson  <mrobinson@igalia.com>
+
+        Reviewed by Gustavo Noronha Silva.
+
+        [GTK] Text copied from a WebView cannot be pasted into gnome-terminal
+        https://bugs.webkit.org/show_bug.cgi?id=39827
+
+        Switch all methods in Pasteboard to use the PasteboardHelper + DataObjectGtk
+        approach used in other parts of WebKit GTK+.
+
+        * platform/gtk/PasteboardGtk.cpp:
+        (WebCore::Pasteboard::writeSelection): Switch to using PasteboardHelper.
+        (WebCore::Pasteboard::writePlainText): Ditto.
+        (WebCore::Pasteboard::writeURL): Ditto.
+        (WebCore::Pasteboard::writeImage): Ditto.
+        (WebCore::Pasteboard::clear): Small cleanup.
+        (WebCore::Pasteboard::documentFragment): Switch to using PasteboardHelper.
+        (WebCore::Pasteboard::plainText): Ditto.
+
 2010-05-31  Darin Adler  <darin@apple.com>
 
         Updated bindings test results for change in JavaScript host calling convention change
index 9e7b23a..599f7da 100644 (file)
@@ -20,6 +20,7 @@
 #include "config.h"
 #include "Pasteboard.h"
 
+#include "DataObjectGtk.h"
 #include "DocumentFragment.h"
 #include "Frame.h"
 #include "NotImplemented.h"
 #include "RenderImage.h"
 #include "KURL.h"
 #include "markup.h"
+#include <wtf/gobject/GRefPtr.h>
 #include <wtf/text/CString.h>
 
 #include <gtk/gtk.h>
 
 namespace WebCore {
 
-class PasteboardSelectionData {
-public:
-    PasteboardSelectionData(gchar* text, gchar* markup)
-        : m_text(text)
-        , m_markup(markup) { }
-
-    ~PasteboardSelectionData() {
-        g_free(m_text);
-        g_free(m_markup);
-    }
-
-    const gchar* text() const { return m_text; }
-    const gchar* markup() const { return m_markup; }
-
-private:
-    gchar* m_text;
-    gchar* m_markup;
-};
-
-static void clipboard_get_contents_cb(GtkClipboard *clipboard, GtkSelectionData *selection_data,
-                                      guint info, gpointer data) {
-    PasteboardSelectionData* clipboardData = reinterpret_cast<PasteboardSelectionData*>(data);
-    ASSERT(clipboardData);
-    if (info == Pasteboard::generalPasteboard()->helper()->getIdForTargetType(PasteboardHelper::TargetTypeMarkup))
-        gtk_selection_data_set(selection_data, selection_data->target, 8,
-                               reinterpret_cast<const guchar*>(clipboardData->markup()),
-                               strlen(clipboardData->markup()));
-    else
-        gtk_selection_data_set_text(selection_data, clipboardData->text(), -1);
-}
-
-static void clipboard_clear_contents_cb(GtkClipboard *clipboard, gpointer data) {
-    PasteboardSelectionData* clipboardData = reinterpret_cast<PasteboardSelectionData*>(data);
-    ASSERT(clipboardData);
-    delete clipboardData;
-}
-
-
 Pasteboard* Pasteboard::generalPasteboard()
 {
     static Pasteboard* pasteboard = new Pasteboard();
@@ -102,22 +66,18 @@ void Pasteboard::setHelper(PasteboardHelper* helper)
 void Pasteboard::writeSelection(Range* selectedRange, bool canSmartCopyOrDelete, Frame* frame)
 {
     GtkClipboard* clipboard = m_helper->getClipboard(frame);
-    gchar* text = g_strdup(frame->selectedText().utf8().data());
-    gchar* markup = g_strdup(createMarkup(selectedRange, 0, AnnotateForInterchange).utf8().data());
-    PasteboardSelectionData* data = new PasteboardSelectionData(text, markup);
-
-    gint n_targets;
-    GtkTargetEntry* targets = gtk_target_table_new_from_list(m_helper->targetList(), &n_targets);
-    gtk_clipboard_set_with_data(clipboard, targets, n_targets,
-                                clipboard_get_contents_cb, clipboard_clear_contents_cb, data);
-    gtk_target_table_free(targets, n_targets);
+    DataObjectGtk* dataObject = DataObjectGtk::forClipboard(clipboard);
+    dataObject->setText(frame->selectedText());
+    dataObject->setMarkup(createMarkup(selectedRange, 0, AnnotateForInterchange));
+    m_helper->writeClipboardContents(clipboard);
 }
 
 void Pasteboard::writePlainText(const String& text)
 {
-    CString utf8 = text.utf8();
     GtkClipboard* clipboard = gtk_clipboard_get_for_display(gdk_display_get_default(), GDK_SELECTION_CLIPBOARD);
-    gtk_clipboard_set_text(clipboard, utf8.data(), utf8.length());
+    DataObjectGtk* dataObject = DataObjectGtk::forClipboard(clipboard);
+    dataObject->setText(text);
+    m_helper->writeClipboardContents(clipboard);
 }
 
 void Pasteboard::writeURL(const KURL& url, const String&, Frame* frame)
@@ -126,10 +86,12 @@ void Pasteboard::writeURL(const KURL& url, const String&, Frame* frame)
         return;
 
     GtkClipboard* clipboard = m_helper->getClipboard(frame);
-    GtkClipboard* primary = m_helper->getPrimarySelectionClipboard(frame);
-    CString utf8 = url.string().utf8();
-    gtk_clipboard_set_text(clipboard, utf8.data(), utf8.length());
-    gtk_clipboard_set_text(primary, utf8.data(), utf8.length());
+    DataObjectGtk* dataObject = DataObjectGtk::forClipboard(clipboard);
+
+    Vector<KURL> uriList;
+    uriList.append(url);
+    dataObject->setURIList(uriList);
+    m_helper->writeClipboardContents(clipboard);
 }
 
 void Pasteboard::writeImage(Node* node, const KURL&, const String&)
@@ -144,16 +106,15 @@ void Pasteboard::writeImage(Node* node, const KURL&, const String&)
     Image* image = cachedImage->image();
     ASSERT(image);
 
-    GdkPixbuf* pixbuf = image->getGdkPixbuf();
-    gtk_clipboard_set_image(clipboard, pixbuf);
-    g_object_unref(pixbuf);
+    GRefPtr<GdkPixbuf> pixbuf = adoptGRef(image->getGdkPixbuf());
+    DataObjectGtk* dataObject = DataObjectGtk::forClipboard(clipboard);
+    dataObject->setImage(pixbuf.get());
+    m_helper->writeClipboardContents(clipboard);
 }
 
 void Pasteboard::clear()
 {
-    GtkClipboard* clipboard = gtk_clipboard_get_for_display(gdk_display_get_default(), GDK_SELECTION_CLIPBOARD);
-
-    gtk_clipboard_clear(clipboard);
+    gtk_clipboard_clear(gtk_clipboard_get_for_display(gdk_display_get_default(), GDK_SELECTION_CLIPBOARD));
 }
 
 bool Pasteboard::canSmartReplace()
@@ -165,33 +126,24 @@ bool Pasteboard::canSmartReplace()
 PassRefPtr<DocumentFragment> Pasteboard::documentFragment(Frame* frame, PassRefPtr<Range> context,
                                                           bool allowPlainText, bool& chosePlainText)
 {
-    GdkAtom textHtml = gdk_atom_intern_static_string("text/html");
     GtkClipboard* clipboard = m_helper->getCurrentClipboard(frame);
+    DataObjectGtk* dataObject = DataObjectGtk::forClipboard(clipboard);
+    m_helper->getClipboardContents(clipboard);
+
     chosePlainText = false;
 
-    if (GtkSelectionData* data = gtk_clipboard_wait_for_contents(clipboard, textHtml)) {
-        ASSERT(data->data);
-        RefPtr<TextResourceDecoder> decoder = TextResourceDecoder::create("text/plain", "UTF-8", true);
-        String html = decoder->decode(reinterpret_cast<char*>(data->data), data->length);
-        html += decoder->flush();
-        gtk_selection_data_free(data);
-
-        if (!html.isEmpty()) {
-            RefPtr<DocumentFragment> fragment = createFragmentFromMarkup(frame->document(), html, "", FragmentScriptingNotAllowed);
-            if (fragment)
-                return fragment.release();
-        }
+    if (dataObject->hasMarkup()) {
+        RefPtr<DocumentFragment> fragment = createFragmentFromMarkup(frame->document(), dataObject->markup(), "", FragmentScriptingNotAllowed);
+        if (fragment)
+            return fragment.release();
     }
 
     if (!allowPlainText)
         return 0;
 
-    if (gchar* utf8 = gtk_clipboard_wait_for_text(clipboard)) {
-        String text = String::fromUTF8(utf8);
-        g_free(utf8);
-
+    if (dataObject->hasText()) {
         chosePlainText = true;
-        RefPtr<DocumentFragment> fragment = createFragmentFromText(context.get(), text);
+        RefPtr<DocumentFragment> fragment = createFragmentFromText(context.get(), dataObject->text());
         if (fragment)
             return fragment.release();
     }
@@ -202,16 +154,10 @@ PassRefPtr<DocumentFragment> Pasteboard::documentFragment(Frame* frame, PassRefP
 String Pasteboard::plainText(Frame* frame)
 {
     GtkClipboard* clipboard = m_helper->getCurrentClipboard(frame);
+    DataObjectGtk* dataObject = DataObjectGtk::forClipboard(clipboard);
 
-    gchar* utf8 = gtk_clipboard_wait_for_text(clipboard);
-
-    if (!utf8)
-        return String();
-
-    String text = String::fromUTF8(utf8);
-    g_free(utf8);
-
-    return text;
+    m_helper->getClipboardContents(clipboard);
+    return dataObject->text();
 }
 
 }
index 9865c26..ec1727d 100644 (file)
@@ -1,3 +1,22 @@
+2010-05-31  Martin Robinson  <mrobinson@igalia.com>
+
+        Reviewed by Gustavo Noronha Silva.
+
+        [GTK] Text copied from a WebView cannot be pasted into gnome-terminal
+        https://bugs.webkit.org/show_bug.cgi?id=39827
+
+        Add a test to prevent regressions for this issue.
+
+        * tests/testcopyandpaste.c: Added.
+        (test_info_new):
+        (test_info_destroy):
+        (copy_and_paste_fixture_setup):
+        (copy_and_paste_fixture_teardown):
+        (load_status_cb):
+        (map_event_cb):
+        (test_copy_and_paste):
+        (main):
+
 2010-05-27  Gustavo Noronha Silva  <gns@gnome.org>
 
         Update documentation control files, and fix Since tags for 1.3.1.
diff --git a/WebKit/gtk/tests/testcopyandpaste.c b/WebKit/gtk/tests/testcopyandpaste.c
new file mode 100644 (file)
index 0000000..034a429
--- /dev/null
@@ -0,0 +1,165 @@
+/*
+ * Copyright (C) 2010 Igalia S.L.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2,1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include <errno.h>
+#include <unistd.h>
+#include <string.h>
+#include <glib/gstdio.h>
+#include <webkit/webkit.h>
+#include <JavaScriptCore/JSStringRef.h>
+#include <JavaScriptCore/JSContextRef.h>
+
+
+#if GTK_CHECK_VERSION(2, 14, 0)
+
+typedef struct {
+    char* page;
+    char* expectedPlainText;
+} TestInfo;
+
+typedef struct {
+    GtkWidget* window;
+    WebKitWebView* webView;
+    GMainLoop* loop;
+    TestInfo* info;
+} CopyAndPasteFixture;
+
+TestInfo*
+test_info_new(const char* page, const char* expectedPlainText)
+{
+    TestInfo* info;
+    info = g_slice_new0(TestInfo);
+    info->page = g_strdup(page);
+    if (expectedPlainText)
+        info->expectedPlainText = g_strdup(expectedPlainText);
+    return info;
+}
+
+void
+test_info_destroy(TestInfo* info)
+{
+    g_free(info->page);
+    g_free(info->expectedPlainText);
+    g_slice_free(TestInfo, info);
+}
+
+static void copy_and_paste_fixture_setup(CopyAndPasteFixture* fixture, gconstpointer data)
+{
+    fixture->loop = g_main_loop_new(NULL, TRUE);
+
+    fixture->window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
+    fixture->webView = WEBKIT_WEB_VIEW(webkit_web_view_new());
+
+    gtk_container_add(GTK_CONTAINER(fixture->window), GTK_WIDGET(fixture->webView));
+}
+
+static void copy_and_paste_fixture_teardown(CopyAndPasteFixture* fixture, gconstpointer data)
+{
+    gtk_widget_destroy(fixture->window);
+    g_main_loop_unref(fixture->loop);
+    test_info_destroy(fixture->info);
+}
+
+static void load_status_cb(WebKitWebView* webView, GParamSpec* spec, gpointer data)
+{
+    CopyAndPasteFixture* fixture = (CopyAndPasteFixture*)data;
+    WebKitLoadStatus status = webkit_web_view_get_load_status(webView);
+    if (status != WEBKIT_LOAD_FINISHED)
+        return;
+
+    GtkClipboard* clipboard = gtk_clipboard_get(GDK_SELECTION_CLIPBOARD);
+    gtk_clipboard_clear(clipboard);
+
+    webkit_web_view_copy_clipboard(webView);
+
+    gchar* text = gtk_clipboard_wait_for_text(clipboard);
+    g_assert(text || !fixture->info->expectedPlainText);
+    g_assert(!text || !strcmp(text, fixture->info->expectedPlainText));
+    g_free(text);
+
+    g_assert(!gtk_clipboard_wait_is_uris_available(clipboard));
+    g_assert(!gtk_clipboard_wait_is_image_available(clipboard));
+
+    g_main_loop_quit(fixture->loop);
+}
+
+gboolean map_event_cb(GtkWidget *widget, GdkEvent* event, gpointer data)
+{
+    gtk_widget_grab_focus(widget);
+    CopyAndPasteFixture* fixture = (CopyAndPasteFixture*)data;
+    webkit_web_view_load_string(fixture->webView, fixture->info->page,
+                                "text/html", "utf-8", "file://");
+    return FALSE;
+}
+
+static void test_copy_and_paste(CopyAndPasteFixture* fixture, gconstpointer data)
+{
+    fixture->info = (TestInfo*)data;
+    g_signal_connect(fixture->window, "map-event",
+                     G_CALLBACK(map_event_cb), fixture);
+
+    gtk_widget_show(fixture->window);
+    gtk_widget_show(GTK_WIDGET(fixture->webView));
+    gtk_window_present(GTK_WINDOW(fixture->window));
+
+    g_signal_connect(fixture->webView, "notify::load-status",
+                     G_CALLBACK(load_status_cb), fixture);
+
+    g_main_loop_run(fixture->loop);
+}
+
+int main(int argc, char** argv)
+{
+    g_thread_init(NULL);
+    gtk_test_init(&argc, &argv, NULL);
+
+    g_test_bug_base("https://bugs.webkit.org/");
+    const char* selected_span_html = "<html><body>"
+        "<span id=\"mainspan\">All work and no play <span>make Jack a dull</span> boy.</span>"
+        "<script>document.getSelection().collapse();\n"
+        "document.getSelection().selectAllChildren(document.getElementById('mainspan'));\n"
+        "</script></body></html>";
+    const char* no_selection_html = "<html><body>"
+        "<span id=\"mainspan\">All work and no play <span>make Jack a dull</span> boy</span>"
+        "<script>document.getSelection().collapse();\n"
+        "</script></body></html>";
+
+    g_test_add("/webkit/copyandpaste/selection", CopyAndPasteFixture,
+               test_info_new(selected_span_html, "All work and no play make Jack a dull boy."),
+               copy_and_paste_fixture_setup,
+               test_copy_and_paste,
+               copy_and_paste_fixture_teardown);
+    g_test_add("/webkit/copyandpaste/no-selection", CopyAndPasteFixture,
+               test_info_new(no_selection_html, 0),
+               copy_and_paste_fixture_setup,
+               test_copy_and_paste,
+               copy_and_paste_fixture_teardown);
+
+    return g_test_run();
+}
+
+#else
+
+int main(int argc, char** argv)
+{
+    g_critical("You will need at least GTK+ 2.14.0 to run the unit tests.");
+    return 0;
+}
+
+#endif