|
From: <sp...@us...> - 2011-08-20 16:38:52
|
Revision: 3620
http://java-game-lib.svn.sourceforge.net/java-game-lib/?rev=3620&view=rev
Author: spasi
Date: 2011-08-20 16:38:45 +0000 (Sat, 20 Aug 2011)
Log Message:
-----------
Text encoding improvements.
Modified Paths:
--------------
trunk/LWJGL/src/java/org/lwjgl/MemoryUtil.java
trunk/LWJGL/src/java/org/lwjgl/WindowsSysImplementation.java
trunk/LWJGL/src/java/org/lwjgl/opengl/LinuxDisplay.java
trunk/LWJGL/src/java/org/lwjgl/opengl/WindowsDisplay.java
trunk/LWJGL/src/native/linux/opengl/org_lwjgl_opengl_Display.c
trunk/LWJGL/src/native/linux/opengles/org_lwjgl_opengl_Display.c
Modified: trunk/LWJGL/src/java/org/lwjgl/MemoryUtil.java
===================================================================
--- trunk/LWJGL/src/java/org/lwjgl/MemoryUtil.java 2011-08-20 11:56:46 UTC (rev 3619)
+++ trunk/LWJGL/src/java/org/lwjgl/MemoryUtil.java 2011-08-20 16:38:45 UTC (rev 3620)
@@ -33,26 +33,28 @@
import java.lang.reflect.Field;
import java.nio.*;
+import java.nio.charset.CharacterCodingException;
import java.nio.charset.Charset;
import java.nio.charset.CharsetEncoder;
+import java.nio.charset.CoderResult;
/**
* [INTERNAL USE ONLY]
* <p/>
- * This class provides utility methods for passing buffer addresses to JNI API calls.
+ * This class provides utility methods for passing buffers to JNI API calls.
*
* @author Spasi
*/
public final class MemoryUtil {
- private static final CharsetEncoder textEncoder;
+ private static final Charset ascii;
+ private static final Charset utf8;
+ private static final Charset utf16;
static {
- CharsetEncoder encoder = Charset.defaultCharset().newEncoder();
- if ( 1.0f < encoder.maxBytesPerChar() )
- encoder = Charset.forName("ISO-8859-1").newEncoder();
-
- textEncoder = encoder;
+ ascii = Charset.forName("ISO-8859-1");
+ utf8 = Charset.forName("UTF-8");
+ utf16 = Charset.forName("UTF-16LE");
}
private static final Accessor memUtil;
@@ -190,63 +192,128 @@
// --- [ String utilities ] ---
/**
- * Returns the specified text as a null-terminated CharBuffer.
+ * Returns a ByteBuffer containing the specified text ASCII encoded and null-terminated.
+ * If text is null, null is returned.
*
* @param text the text to encode
*
- * @return the encoded text
+ * @return the encoded text or null
+ *
+ * @see String#getBytes()
*/
- public static CharBuffer encodeUTF16(final CharSequence text) {
- CharBuffer buffer = BufferUtils.createCharBuffer(text.length() + 1);
- buffer.append(text).append('\0');
- buffer.flip();
- return buffer;
+ public static ByteBuffer encodeASCII(final CharSequence text) {
+ return encode(text, ascii);
}
/**
- * Returns the specified text array as a CharBuffer. The CharBuffer is packed
- * and each text is null-terminated.
+ * Returns a ByteBuffer containing the specified text UTF-8 encoded and null-terminated.
+ * If text is null, null is returned.
*
- * @param text the text array to encode
+ * @param text the text to encode
*
- * @return the encoded text
+ * @return the encoded text or null
+ *
+ * @see String#getBytes()
*/
- public static CharBuffer encodeUTF16(final CharSequence... text) {
- int len = 0;
- for ( CharSequence cs : text )
- len += cs.length();
-
- final CharBuffer buffer = BufferUtils.createCharBuffer(len + text.length);
- for ( CharSequence cs : text )
- buffer.append(cs).append('\0');
-
- buffer.flip();
- return buffer;
+ public static ByteBuffer encodeUTF8(final CharSequence text) {
+ return encode(text, utf8);
}
/**
- * Encodes and null-terminated the specified text and returns a ByteBuffer.
+ * Returns a ByteBuffer containing the specified text UTF-16LE encoded and null-terminated.
* If text is null, null is returned.
*
* @param text the text to encode
*
- * @return the encoded text or null
+ * @return the encoded text
+ */
+ public static ByteBuffer encodeUTF16(final CharSequence text) {
+ return encode(text, utf16);
+ }
+
+ /**
+ * Wraps the specified text in a null-terminated CharBuffer and encodes it using the specified Charset.
*
- * @see String#getBytes()
+ * @param text the text to encode
+ * @param charset the charset to use for encoding
+ *
+ * @return the encoded text
*/
- public static ByteBuffer encodeASCII(final CharSequence text) {
+ private static ByteBuffer encode(final CharSequence text, final Charset charset) {
if ( text == null )
return null;
- final ByteBuffer buffer = BufferUtils.createByteBuffer(text.length() + 1);
+ return encode(CharBuffer.wrap(new CharSequenceNT(text)), charset);
+ }
- textEncoder.encode(CharBuffer.wrap(text), buffer, true);
- buffer.put((byte)0);
- buffer.flip();
+ /**
+ * A {@link CharsetEncoder#encode(java.nio.CharBuffer)} implementation that uses {@link BufferUtils#createByteBuffer(int)}
+ * instead of {@link ByteBuffer#allocate(int)}.
+ *
+ * @see CharsetEncoder#encode(java.nio.CharBuffer)
+ */
+ private static ByteBuffer encode(final CharBuffer in, final Charset charset) {
+ final CharsetEncoder encoder = charset.newEncoder(); // encoders are not thread-safe, create a new one on every call
- return buffer;
+ int n = (int)(in.remaining() * encoder.averageBytesPerChar());
+ ByteBuffer out = BufferUtils.createByteBuffer(n);
+
+ if ( n == 0 && in.remaining() == 0 )
+ return out;
+
+ encoder.reset();
+ while ( true ) {
+ CoderResult cr = in.hasRemaining() ? encoder.encode(in, out, true) : CoderResult.UNDERFLOW;
+ if ( cr.isUnderflow() )
+ cr = encoder.flush(out);
+
+ if ( cr.isUnderflow() )
+ break;
+
+ if ( cr.isOverflow() ) {
+ n = 2 * n + 1; // Ensure progress; n might be 0!
+ ByteBuffer o = BufferUtils.createByteBuffer(n);
+ out.flip();
+ o.put(out);
+ out = o;
+ continue;
+ }
+
+ try {
+ cr.throwException();
+ } catch (CharacterCodingException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ out.flip();
+ return out;
}
+ /** A null-terminated CharSequence. */
+ private static class CharSequenceNT implements CharSequence {
+
+ final CharSequence source;
+
+ CharSequenceNT(CharSequence source) {
+ this.source = source;
+ }
+
+ public int length() {
+ return source.length() + 1;
+
+ }
+
+ public char charAt(final int index) {
+ return index == source.length() ? '\0' : source.charAt(index);
+
+ }
+
+ public CharSequence subSequence(final int start, final int end) {
+ return new CharSequenceNT(source.subSequence(start, Math.min(end, source.length())));
+ }
+
+ }
+
interface Accessor {
long getAddress(Buffer buffer);
@@ -307,4 +374,4 @@
throw new NoSuchFieldException(fieldName + " does not exist in " + type.getSimpleName() + " or any of its superclasses.");
}
-}
\ No newline at end of file
+}
Modified: trunk/LWJGL/src/java/org/lwjgl/WindowsSysImplementation.java
===================================================================
--- trunk/LWJGL/src/java/org/lwjgl/WindowsSysImplementation.java 2011-08-20 11:56:46 UTC (rev 3619)
+++ trunk/LWJGL/src/java/org/lwjgl/WindowsSysImplementation.java 2011-08-20 16:38:45 UTC (rev 3620)
@@ -31,7 +31,7 @@
*/
package org.lwjgl;
-import java.nio.CharBuffer;
+import java.nio.ByteBuffer;
import java.security.PrivilegedExceptionAction;
import java.security.PrivilegedActionException;
import java.security.AccessController;
@@ -99,10 +99,9 @@
LWJGLUtil.log(String.format("*** Alert *** %s\n%s\n", title, message));
- // Pack both strings in the same buffer
- final CharBuffer buffer = MemoryUtil.encodeUTF16(title, message);
- final long address = MemoryUtil.getAddress0(buffer);
- nAlert(getHwnd(), address, address + (title.length() + 1) * 2);
+ final ByteBuffer titleText = MemoryUtil.encodeUTF16(title);
+ final ByteBuffer messageText = MemoryUtil.encodeUTF16(message);
+ nAlert(getHwnd(), MemoryUtil.getAddress(titleText), MemoryUtil.getAddress(messageText));
}
private static native void nAlert(long parent_hwnd, long title, long message);
private static native void initCommonControls();
Modified: trunk/LWJGL/src/java/org/lwjgl/opengl/LinuxDisplay.java
===================================================================
--- trunk/LWJGL/src/java/org/lwjgl/opengl/LinuxDisplay.java 2011-08-20 11:56:46 UTC (rev 3619)
+++ trunk/LWJGL/src/java/org/lwjgl/opengl/LinuxDisplay.java 2011-08-20 16:38:45 UTC (rev 3620)
@@ -53,6 +53,7 @@
import org.lwjgl.BufferUtils;
import org.lwjgl.LWJGLException;
import org.lwjgl.LWJGLUtil;
+import org.lwjgl.MemoryUtil;
import org.lwjgl.opengl.XRandR.Screen;
import org.lwjgl.opengles.EGL;
@@ -138,7 +139,7 @@
private long current_cursor;
private long blank_cursor;
private boolean mouseInside = true;
-
+
private Canvas parent;
private long parent_window;
private boolean xembedded;
@@ -148,7 +149,7 @@
private LinuxKeyboard keyboard;
private LinuxMouse mouse;
-
+
private final FocusListener focus_listener = new FocusListener() {
public void focusGained(FocusEvent e) {
synchronized (GlobalLock.lock) {
@@ -499,7 +500,7 @@
private static native void reparentWindow(long display, long window, long parent, int x, int y);
private static native long nGetInputFocus(long display) throws LWJGLException;
private static native void nSetInputFocus(long display, long window, long time);
-
+
private static boolean isAncestorXEmbedded(long window) throws LWJGLException {
long xembed_atom = internAtom("_XEMBED_INFO", true);
if (xembed_atom != None) {
@@ -728,12 +729,13 @@
public void setTitle(String title) {
lockAWT();
try {
- nSetTitle(getDisplay(), getWindow(), title);
+ final ByteBuffer titleText = MemoryUtil.encodeUTF8(title);
+ nSetTitle(getDisplay(), getWindow(), MemoryUtil.getAddress(titleText), titleText.remaining() - 1);
} finally {
unlockAWT();
}
}
- private static native void nSetTitle(long display, long window, String title);
+ private static native void nSetTitle(long display, long window, long title, int len);
public boolean isCloseRequested() {
boolean result = close_requested;
@@ -915,19 +917,19 @@
unlockAWT();
}
}
-
+
private void checkInput() {
if (parent == null) return;
-
+
if (xembedded) {
long current_focus_window = 0;
-
+
try {
current_focus_window = nGetInputFocus(getDisplay());
} catch (LWJGLException e) {
return; // fail silently as it can fail whilst splitting browser tabs
}
-
+
if (last_window_focus != current_focus_window || parent_focused != focused) {
if (isParentWindowActive(current_focus_window)) {
if (parent_focused) {
@@ -963,49 +965,49 @@
}
}
}
-
+
/**
* This method will check if the parent window is active when running
- * in xembed mode. Every xembed embedder window has a focus proxy
- * window that recieves all the input. This method will test whether
- * the provided window handle is the focus proxy, if so it will get its
+ * in xembed mode. Every xembed embedder window has a focus proxy
+ * window that recieves all the input. This method will test whether
+ * the provided window handle is the focus proxy, if so it will get its
* parent window and then test whether this is an ancestor to our
* current_window. If so then parent window is active.
- *
+ *
* @param window - the window handle to test
*/
private boolean isParentWindowActive(long window) {
try {
// parent window already active as window is current_window
if (window == current_window) return true;
-
+
// xembed focus proxy will have no children
if (getChildCount(getDisplay(), window) != 0) return false;
-
+
// get parent, will be xembed embedder window and ancestor of current_window
long parent_window = getParentWindow(getDisplay(), window);
-
+
// parent must not be None
if (parent_window == None) return false;
-
+
// scroll current_window's ancestors to find parent_window
long w = current_window;
-
+
while (w != None) {
w = getParentWindow(getDisplay(), w);
if (w == parent_window) {
parent_proxy_focus_window = window; // save focus proxy window
return true;
}
- }
+ }
} catch (LWJGLException e) {
LWJGLUtil.log("Failed to detect if parent window is active: " + e.getMessage());
return true; // on failure assume still active
}
-
+
return false; // failed to find an active parent window
}
-
+
private void setFocused(boolean got_focus, int focus_detail) {
if (focused == got_focus || focus_detail == NotifyDetailNone || focus_detail == NotifyPointer || focus_detail == NotifyPointerRoot || parent != null)
return;
@@ -1356,11 +1358,11 @@
public boolean isInsideWindow() {
return mouseInside;
}
-
+
public void setResizable(boolean resizable) {
-
+
}
-
+
public boolean wasResized() {
return false;
}
@@ -1552,4 +1554,4 @@
}
}
-}
\ No newline at end of file
+}
Modified: trunk/LWJGL/src/java/org/lwjgl/opengl/WindowsDisplay.java
===================================================================
--- trunk/LWJGL/src/java/org/lwjgl/opengl/WindowsDisplay.java 2011-08-20 11:56:46 UTC (rev 3619)
+++ trunk/LWJGL/src/java/org/lwjgl/opengl/WindowsDisplay.java 2011-08-20 16:38:45 UTC (rev 3620)
@@ -438,7 +438,7 @@
private static native DisplayMode getCurrentDisplayMode() throws LWJGLException;
public void setTitle(String title) {
- CharBuffer buffer = MemoryUtil.encodeUTF16(title);
+ ByteBuffer buffer = MemoryUtil.encodeUTF16(title);
nSetTitle(hwnd, MemoryUtil.getAddress0(buffer));
}
private static native void nSetTitle(long hwnd, long title);
Modified: trunk/LWJGL/src/native/linux/opengl/org_lwjgl_opengl_Display.c
===================================================================
--- trunk/LWJGL/src/native/linux/opengl/org_lwjgl_opengl_Display.c 2011-08-20 11:56:46 UTC (rev 3619)
+++ trunk/LWJGL/src/native/linux/opengl/org_lwjgl_opengl_Display.c 2011-08-20 16:38:45 UTC (rev 3620)
@@ -1,31 +1,31 @@
-/*
+/*
* Copyright (c) 2002-2008 LWJGL Project
* All rights reserved.
- *
+ *
* Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
+ * modification, are permitted provided that the following conditions are
* met:
- *
- * * Redistributions of source code must retain the above copyright
+ *
+ * * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
- * * Neither the name of 'LWJGL' nor the names of
- * its contributors may be used to endorse or promote products derived
+ * * Neither the name of 'LWJGL' nor the names of
+ * its contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
- *
+ *
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
- * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
@@ -72,8 +72,8 @@
static Colormap cmap;
static int current_depth;
-static Pixmap current_icon_pixmap;
-static Pixmap current_icon_mask_pixmap;
+static Pixmap current_icon_pixmap;
+static Pixmap current_icon_mask_pixmap;
static Visual *current_visual;
@@ -94,7 +94,7 @@
jmethodID handler_method = (*env)->GetStaticMethodID(env, org_lwjgl_LinuxDisplay_class, "globalErrorHandler", "(JJJJJJJ)I");
if (handler_method == NULL)
return 0;
- return (*env)->CallStaticIntMethod(env, org_lwjgl_LinuxDisplay_class, handler_method, (jlong)(intptr_t)disp, (jlong)(intptr_t)error,
+ return (*env)->CallStaticIntMethod(env, org_lwjgl_LinuxDisplay_class, handler_method, (jlong)(intptr_t)disp, (jlong)(intptr_t)error,
(jlong)(intptr_t)error->display, (jlong)error->serial, (jlong)error->error_code, (jlong)error->request_code, (jlong)error->minor_code);
} else
return 0;
@@ -170,15 +170,16 @@
return window_mode == org_lwjgl_opengl_LinuxDisplay_FULLSCREEN_LEGACY;
}
-static void setWindowTitle(Display *disp, Window window, const char *title) {
- XStoreName(disp, window, title);
+static void setWindowTitle(Display *disp, Window window, jlong title, jint len) {
+ // ASCII fallback if XChangeProperty fails.
+ XStoreName(disp, window, (const char *)(intptr_t)title);
- // tell WM to use Unicode
+ // Set the UTF-8 encoded title
XChangeProperty(disp, window,
XInternAtom(disp, "_NET_WM_NAME", False),
XInternAtom(disp, "UTF8_STRING", False),
- 8, PropModeReplace, (unsigned char *) title,
- strlen(title));
+ 8, PropModeReplace, (const char *)(intptr_t)title,
+ len);
}
JNIEXPORT jlong JNICALL Java_org_lwjgl_opengl_LinuxDisplay_openDisplay(JNIEnv *env, jclass clazz) {
@@ -202,13 +203,11 @@
Display *disp = (Display *)(intptr_t)display;
initPeerInfo(env, peer_info_handle, disp, screen, pixel_format, true, GLX_WINDOW_BIT, true, false);
}
-
-JNIEXPORT void JNICALL Java_org_lwjgl_opengl_LinuxDisplay_nSetTitle(JNIEnv * env, jclass clazz, jlong display, jlong window_ptr, jstring title_obj) {
+
+JNIEXPORT void JNICALL Java_org_lwjgl_opengl_LinuxDisplay_nSetTitle(JNIEnv * env, jclass clazz, jlong display, jlong window_ptr, jlong title, jint len) {
Display *disp = (Display *)(intptr_t)display;
Window window = (Window)window_ptr;
- char * title = GetStringNativeChars(env, title_obj);
- setWindowTitle(disp, window, title);
- free(title);
+ setWindowTitle(disp, window, title, len);
}
static void freeIconPixmap(Display *disp) {
@@ -285,7 +284,7 @@
throwException(env, "XAllocWMHints failed");
return;
}
-
+
win_hints->flags = InputHint;
win_hints->input = True;
if (current_icon_pixmap != 0) {
@@ -321,10 +320,10 @@
attribs.override_redirect = True;
}
win = XCreateWindow(disp, parent, x, y, width, height, 0, vis_info->depth, InputOutput, vis_info->visual, attribmask, &attribs);
-
+
current_depth = vis_info->depth;
current_visual = vis_info->visual;
-
+
XFree(vis_info);
if (!checkXError(env, disp)) {
XFreeColormap(disp, cmap);
@@ -511,7 +510,7 @@
throwException(env, "XCreateImage failed");
return None;
}
-
+
GC gc = XCreateGC(disp, pixmap, 0, NULL);
XPutImage(disp, pixmap, gc, image, 0, 0, 0, 0, width, height);
XFreeGC(disp, gc);
@@ -530,7 +529,7 @@
freeIconPixmap(disp);
return;
}
-
+
updateWindowHints(env, disp, window);
}
Modified: trunk/LWJGL/src/native/linux/opengles/org_lwjgl_opengl_Display.c
===================================================================
--- trunk/LWJGL/src/native/linux/opengles/org_lwjgl_opengl_Display.c 2011-08-20 11:56:46 UTC (rev 3619)
+++ trunk/LWJGL/src/native/linux/opengles/org_lwjgl_opengl_Display.c 2011-08-20 16:38:45 UTC (rev 3620)
@@ -167,15 +167,16 @@
return window_mode == org_lwjgl_opengl_LinuxDisplay_FULLSCREEN_LEGACY;
}
-static void setWindowTitle(Display *disp, Window window, const char *title) {
- XStoreName(disp, window, title);
+static void setWindowTitle(Display *disp, Window window, jlong title, jint len) {
+ // ASCII fallback if XChangeProperty fails.
+ XStoreName(disp, window, (const char *)(intptr_t)title);
- // tell WM to use Unicode
+ // Set the UTF-8 encoded title
XChangeProperty(disp, window,
XInternAtom(disp, "_NET_WM_NAME", False),
XInternAtom(disp, "UTF8_STRING", False),
- 8, PropModeReplace, (unsigned char *) title,
- strlen(title));
+ 8, PropModeReplace, (const char *)(intptr_t)title,
+ len);
}
JNIEXPORT jlong JNICALL Java_org_lwjgl_opengl_LinuxDisplay_openDisplay(JNIEnv *env, jclass clazz) {
@@ -197,12 +198,10 @@
//initPeerInfo(env, peer_info_handle, disp, screen);
}
-JNIEXPORT void JNICALL Java_org_lwjgl_opengl_LinuxDisplay_nSetTitle(JNIEnv * env, jclass clazz, jlong display, jlong window_ptr, jstring title_obj) {
+JNIEXPORT void JNICALL Java_org_lwjgl_opengl_LinuxDisplay_nSetTitle(JNIEnv * env, jclass clazz, jlong display, jlong window_ptr, jlong title, jint len) {
Display *disp = (Display *)(intptr_t)display;
Window window = (Window)window_ptr;
- char * title = GetStringNativeChars(env, title_obj);
- setWindowTitle(disp, window, title);
- free(title);
+ setWindowTitle(disp, window, title, len);
}
static void freeIconPixmap(Display *disp) {
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|