changeset 5199:4f279342c9b3

RT-32705: TextField/TextArea: on Windows, ArrayIndexOutOfBoundsException for complex Thai characters.
author Felipe Heidrich <felipe.heidrich@oracle.com>
date Fri, 27 Sep 2013 09:40:26 -0700
parents c368675b0728
children d8f1608ffe71
files modules/graphics/src/main/java/com/sun/javafx/font/directwrite/DWGlyphLayout.java modules/graphics/src/main/java/com/sun/javafx/font/directwrite/JFXTextRenderer.java modules/graphics/src/main/java/com/sun/javafx/font/directwrite/OS.java modules/graphics/src/main/native-font/directwrite.cpp
diffstat 4 files changed, 43 insertions(+), 23 deletions(-) [+]
line wrap: on
line diff
--- a/modules/graphics/src/main/java/com/sun/javafx/font/directwrite/DWGlyphLayout.java	Fri Sep 27 09:29:32 2013 -0700
+++ b/modules/graphics/src/main/java/com/sun/javafx/font/directwrite/DWGlyphLayout.java	Fri Sep 27 09:40:26 2013 -0700
@@ -25,6 +25,8 @@
 
 package com.sun.javafx.font.directwrite;
 
+import java.util.Arrays;
+
 import com.sun.javafx.font.CompositeFontResource;
 import com.sun.javafx.font.FontResource;
 import com.sun.javafx.font.FontStrike;
@@ -144,15 +146,6 @@
                                     analysis, null, features, featuresRangeLengths,
                                     featuresCount, advances, offsets);
 
-        /* Adjust glyph indices */
-        int[] indices = new int[length];
-        i = 0; j = rtl ? length - 1 : 0;
-        while (i < length) {
-            indices[i] = clusterMap[j];
-            i++;
-            j+=step;
-        }
-
         /* Adjust glyphs positions */
         float[] pos = new float[glyphCount * 2 + 2];
         i = 0; j = rtl ? glyphCount - 1 : 0;
@@ -168,9 +161,41 @@
         pos[i++] = 0;
 
         analyzer.Release();
+        int[] indices = getIndices(clusterMap, glyphCount, rtl);
         run.shape(glyphCount, iglyphs, pos, indices);
     }
 
+    private int[] getIndices(short[] clusterMap, int glyphCount, boolean rtl) {
+        /* The cluster map array produced by DirectWrite is character offset
+         * to glyph index mapping. TextRun internally requires a glyph index
+         * to character offset map table. */
+        int[] indices = new int[glyphCount];
+        Arrays.fill(indices, -1);
+        for (int i = 0; i < clusterMap.length; i++) {
+            /* keep character offset for the first glyph in the cluster */
+            if (indices[clusterMap[i]] == -1) {
+                indices[clusterMap[i]] = i;
+            }
+        }
+        if (indices.length > 0) {
+            if (indices[0] == -1) indices[0] = 0;
+            /* use the character offset of the preceding element */
+            for (int i = 1; i < indices.length; i++) {
+                if (indices[i] == -1) indices[i] = indices[i - 1];
+            }
+        }
+
+        if (rtl) {
+            /* Flip the array for RTL */
+            for (int i = 0; i < indices.length / 2; i++) {
+                int tmp = indices[i];
+                indices[i] = indices[indices.length - i - 1];
+                indices[indices.length - i - 1] = tmp;
+            }
+        }
+        return indices;
+    }
+
     private String getName(IDWriteLocalizedStrings localizedStrings) {
         if (localizedStrings == null) return null;
         int index = localizedStrings.FindLocaleName(LOCALE);
@@ -314,7 +339,7 @@
         int[] glyphs = new int[glyphCount];
         float[] advances = new float[glyphCount];
         float[] offsets = new float[glyphCount * 2];
-        int[] clusterMap = new int[length];
+        short[] clusterMap = new short[length];
         int glyphStart = 0;
         int textStart = 0;
         while (renderer.Next()) {
@@ -358,13 +383,8 @@
                 glyphs[i] = glyphs[glyphCount - i - 1];
                 glyphs[glyphCount - i - 1] = tmp;
             }
-            /* Adjust glyph indices */
-            for (i = 0; i < length / 2; i++) {
-                int tmp = clusterMap[i];
-                clusterMap[i] = clusterMap[length - i - 1];
-                clusterMap[length - i - 1] = tmp;
-            }
         }
-        run.shape(glyphCount, glyphs, pos, clusterMap);
+        int[] indices = getIndices(clusterMap, glyphCount, rtl);
+        run.shape(glyphCount, glyphs, pos, indices);
     }
 }
--- a/modules/graphics/src/main/java/com/sun/javafx/font/directwrite/JFXTextRenderer.java	Fri Sep 27 09:29:32 2013 -0700
+++ b/modules/graphics/src/main/java/com/sun/javafx/font/directwrite/JFXTextRenderer.java	Fri Sep 27 09:40:26 2013 -0700
@@ -68,7 +68,7 @@
         return OS.JFXTextRendererGetGlyphOffsets(ptr, offsets, start);
     }
 
-    int GetClusterMap(int[] clusterMap, int start) {
+    int GetClusterMap(short[] clusterMap, int start) {
         return OS.JFXTextRendererGetClusterMap(ptr, clusterMap, start);
     }
 }
--- a/modules/graphics/src/main/java/com/sun/javafx/font/directwrite/OS.java	Fri Sep 27 09:29:32 2013 -0700
+++ b/modules/graphics/src/main/java/com/sun/javafx/font/directwrite/OS.java	Fri Sep 27 09:40:26 2013 -0700
@@ -225,7 +225,7 @@
     static final native int JFXTextRendererGetGlyphIndices(long ptr, int[] glyphs, int start, int slot);
     static final native int JFXTextRendererGetGlyphAdvances(long ptr, float[] advances, int start);
     static final native int JFXTextRendererGetGlyphOffsets(long ptr, float[] offsets, int start);
-    static final native int JFXTextRendererGetClusterMap(long ptr, int[] clusterMap, int start);
+    static final native int JFXTextRendererGetClusterMap(long ptr, short[] clusterMap, int start);
 
     //IDWriteFontFace
     static final native int GetType(long ptr);
--- a/modules/graphics/src/main/native-font/directwrite.cpp	Fri Sep 27 09:29:32 2013 -0700
+++ b/modules/graphics/src/main/native-font/directwrite.cpp	Fri Sep 27 09:40:26 2013 -0700
@@ -1270,9 +1270,9 @@
 }
 
 JNIEXPORT jint JNICALL OS_NATIVE(JFXTextRendererGetClusterMap)
-(JNIEnv *env, jclass that, jlong arg0, jintArray arg1, jint start) {
+(JNIEnv *env, jclass that, jlong arg0, jshortArray arg1, jint start) {
     if (!arg1) return 0;
-    jint* data = env->GetIntArrayElements(arg1, NULL);
+    jshort* data = env->GetShortArrayElements(arg1, NULL);
     if (!data) return 0;
 
     JFXTextRenderer* renderer = (JFXTextRenderer*)arg0;
@@ -1287,9 +1287,9 @@
      * by DirectWrite has it relative to the DWRITE_GLYPH_RUN.
      */
     for (i = 0; i < copiedCount; i++) {
-        data[i + start] = map[i] + start;
+        data[i + start] = map[i] + (jshort)start;
     }
-    env->ReleaseIntArrayElements(arg1, data, NULL);
+    env->ReleaseShortArrayElements(arg1, data, NULL);
     return copiedCount;
 }