--- old/modules/javafx.graphics/src/main/native-glass/gtk/GlassSystemClipboard.cpp 2017-05-05 20:23:07.437745942 -0700 +++ new/modules/javafx.graphics/src/main/native-glass/gtk/GlassSystemClipboard.cpp 2017-05-05 20:23:07.261759653 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -37,6 +37,12 @@ static GdkAtom MIME_FILES_TARGET; +static jmethodID String_init_ID; + +static jmethodID String_getBytes_ID; + +static jstring charset; + static void init_atoms() { static int initialized = 0; @@ -49,6 +55,18 @@ MIME_JAVA_IMAGE = gdk_atom_intern_static_string("application/x-java-rawimage"); MIME_FILES_TARGET = gdk_atom_intern_static_string("application/x-java-file-list"); + + String_init_ID = mainEnv->GetMethodID(jStringCls, + "", "([BLjava/lang/String;)V"); + + String_getBytes_ID = mainEnv->GetMethodID(jStringCls, + "getBytes", "(Ljava/lang/String;)[B"); + + jstring set = mainEnv->NewStringUTF("UTF-8"); + CHECK_JNI_EXCEPTION(mainEnv); + charset = (jstring)mainEnv->NewGlobalRef(set); + mainEnv->DeleteLocalRef(set); + initialized = 1; } } @@ -65,9 +83,39 @@ return clipboard; } +static jobject createUTF(JNIEnv *env, char *data) { + int len; + jbyteArray ba; + jobject jdata; + len = strlen(data); + ba = env->NewByteArray(len); + EXCEPTION_OCCURED(env); + env->SetByteArrayRegion(ba, 0, len, (jbyte *)data); + EXCEPTION_OCCURED(env); + jdata = env->NewObject(jStringCls, String_init_ID, ba, charset); + env->DeleteLocalRef(ba); + EXCEPTION_OCCURED(env); + return jdata; +} + +static char *getUTF(JNIEnv *env, jstring str) { + jbyteArray ba; + jsize len; + char *data; + ba = (jbyteArray) env->CallObjectMethod(str, String_getBytes_ID, charset); + EXCEPTION_OCCURED(env); + len = env->GetArrayLength(ba); + data = (char *)g_malloc(len + 1); + env->GetByteArrayRegion(ba, 0, len, (jbyte *)data); + env->DeleteLocalRef(ba); + EXCEPTION_OCCURED(env); + data[len] = 0; + return data; +} + static void add_target_from_jstring(JNIEnv *env, GtkTargetList *list, jstring string) { - const char *gstring = env->GetStringUTFChars(string, NULL); + const char *gstring = getUTF(env, string); if (g_strcmp0(gstring, "text/plain") == 0) { gtk_target_list_add_text_targets(list, 0); } else if (g_strcmp0(gstring, "application/x-java-rawimage") == 0) { @@ -78,7 +126,7 @@ gtk_target_list_add(list, gdk_atom_intern(gstring, FALSE), 0, 0); } - env->ReleaseStringUTFChars(string, gstring); + g_free((gpointer)gstring); } static void data_to_targets(JNIEnv *env, jobject data, GtkTargetEntry **targets, gint *ntargets) @@ -105,21 +153,21 @@ static void set_text_data(GtkSelectionData *selection_data, jstring data) { - const char *text_data = mainEnv->GetStringUTFChars(data, NULL); + const char *text_data = getUTF(mainEnv, data); guint ntext_data = strlen(text_data); gtk_selection_data_set_text(selection_data, text_data, ntext_data); - mainEnv->ReleaseStringUTFChars(data, text_data); + g_free((gpointer)text_data); } static void set_jstring_data(GtkSelectionData *selection_data, GdkAtom target, jstring data) { - const char *text_data = mainEnv->GetStringUTFChars(data, NULL); + const char *text_data = getUTF(mainEnv, data); guint ntext_data = strlen(text_data); //XXX is target == type ?? gtk_selection_data_set(selection_data, target, 8, (const guchar *)text_data, ntext_data); - mainEnv->ReleaseStringUTFChars(data, text_data); + g_free((gpointer)text_data); } static void set_bytebuffer_data(GtkSelectionData *selection_data, GdkAtom target, jobject data) @@ -149,7 +197,7 @@ if (mainEnv->CallBooleanMethod(data, jMapContainsKey, typeString, NULL)) { jurl = (jstring) mainEnv->CallObjectMethod(data, jMapGet, typeString, NULL); CHECK_JNI_EXCEPTION(mainEnv); - url = mainEnv->GetStringUTFChars(jurl, NULL); + url = getUTF(mainEnv, jurl); } typeString = mainEnv->NewStringUTF("application/x-java-file-list"); @@ -173,7 +221,7 @@ sizeof(gchar*)); if (!uris) { if (url) { - mainEnv->ReleaseStringUTFChars(jurl, url); + g_free((gpointer)url); } glass_throw_oom(mainEnv, "Failed to allocate uri data"); return; @@ -183,9 +231,9 @@ if (files_cnt > 0) { for (; i < files_cnt; ++i) { jstring string = (jstring) mainEnv->GetObjectArrayElement(files_array, i); - const gchar* file = mainEnv->GetStringUTFChars(string, NULL); + const gchar* file = getUTF(mainEnv, string); uris[i] = g_filename_to_uri(file, NULL, NULL); - mainEnv->ReleaseStringUTFChars(string, file); + g_free((gpointer)file); } } @@ -202,7 +250,7 @@ } if (url) { - mainEnv->ReleaseStringUTFChars(jurl, url); + g_free((gpointer)url); } g_free(uris); } @@ -285,7 +333,7 @@ if (data == NULL) { return NULL; } - jstring jdata = env->NewStringUTF(data); + jobject jdata = createUTF(env, data); EXCEPTION_OCCURED(env); g_free(data); return jdata; @@ -350,7 +398,7 @@ if (data != NULL) { raw_data = glass_gtk_selection_data_get_data_with_length(data, &length); if (string_data) { - result = env->NewStringUTF((const char*)raw_data); + result = createUTF(env, (char*)raw_data); EXCEPTION_OCCURED(env); } else { array = env->NewByteArray(length); --- /dev/null 2017-05-04 07:53:01.211588483 -0700 +++ new/tests/system/src/test/java/test/javafx/scene/input/ClipboardTest.java 2017-05-05 20:23:07.689726310 -0700 @@ -0,0 +1,121 @@ +/* + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code 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 General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package test.javafx.scene.input; + +import javafx.application.Platform; +import javafx.scene.input.Clipboard; +import javafx.scene.input.ClipboardContent; +import javafx.scene.input.DataFormat; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Test; +import test.util.Util; + +import java.awt.*; +import java.awt.datatransfer.DataFlavor; +import java.awt.datatransfer.StringSelection; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +import static junit.framework.TestCase.fail; +import static org.junit.Assert.assertEquals; + + +public class ClipboardTest { + static CountDownLatch startupLatch; + static Clipboard clipboard; + + + public static void main(String[] args) throws Exception { + initFX(); + try { + ClipboardTest test = new ClipboardTest(); + test.testCopyUTF8String(); + test.testPasteUTF8String(); + } catch (Throwable e) { + e.printStackTrace(); + } finally { + teardown(); + } + } + + @BeforeClass + public static void initFX() { + startupLatch = new CountDownLatch(1); + Platform.startup(() -> { + clipboard = Clipboard.getSystemClipboard(); + startupLatch.countDown(); + }); + try { + if (!startupLatch.await(15, TimeUnit.SECONDS)) { + fail("Timeout waiting for FX runtime to start"); + } + } catch (InterruptedException ex) { + fail("Unexpected exception: " + ex); + } + } + + @Test + public void testCopyUTF8String() throws Exception { + String text = new String(new byte[]{ + 0x20, (byte) 0x4a, (byte) 0x75, (byte) 0x6d, (byte) 0x70, (byte) 0x20, + (byte) 0x74, (byte) 0x6f, (byte) 0x3a, (byte) 0x20, (byte) 0xf0, + (byte) 0x9f, (byte) 0x98, (byte) 0x83, (byte) 0xf0, (byte) 0x9f, + (byte) 0x92, (byte) 0x81, (byte) 0x20, (byte) 0x4a, (byte) 0x75, + (byte) 0x6d, (byte) 0x70 + }, "UTF-8"); + + ClipboardContent content = new ClipboardContent(); + content.putString(text); + Util.runAndWait(() -> clipboard.setContent(content)); + Thread.sleep(1000); + + assertEquals(text, Toolkit.getDefaultToolkit() + .getSystemClipboard().getData(DataFlavor.stringFlavor)); + } + + @Test + public void testPasteUTF8String() throws Exception { + String text = new String(new byte[]{ + 0x20, (byte) 0x4a, (byte) 0x75, (byte) 0x6d, (byte) 0x70, (byte) 0x20, + (byte) 0x74, (byte) 0x6f, (byte) 0x3a, (byte) 0x20, (byte) 0xf0, + (byte) 0x9f, (byte) 0x98, (byte) 0x83, (byte) 0xf0, (byte) 0x9f, + (byte) 0x92, (byte) 0x81, (byte) 0x20, (byte) 0x4a, (byte) 0x75, + (byte) 0x6d, (byte) 0x70 + }, "UTF-8"); + + Toolkit.getDefaultToolkit() + .getSystemClipboard().setContents(new StringSelection(text), null); + + Thread.sleep(1000); + Util.runAndWait(() -> + assertEquals(text, clipboard.getContent(DataFormat.PLAIN_TEXT))); + } + + @AfterClass + public static void teardown() { + Platform.exit(); + } +}