jdk/src/java.desktop/share/native/libfontmanager/HBShaper.c
changeset 40992 788c9cca556f
parent 40988 cc334ef95225
child 41003 054df19db18c
--- a/jdk/src/java.desktop/share/native/libfontmanager/HBShaper.c	Thu Sep 01 16:18:14 2016 +0530
+++ b/jdk/src/java.desktop/share/native/libfontmanager/HBShaper.c	Thu Sep 01 11:29:20 2016 -0700
@@ -40,6 +40,7 @@
 static jfieldID gvdGlyphsFID = 0;
 static jfieldID gvdPositionsFID = 0;
 static jfieldID gvdIndicesFID = 0;
+static jmethodID gvdGrowMID = 0;
 static int jniInited = 0;
 
 static void getFloat(JNIEnv* env, jobject pt, jfloat *x, jfloat *y) {
@@ -63,73 +64,88 @@
     CHECK_NULL_RETURN(gvdGlyphsFID = (*env)->GetFieldID(env, gvdClass, "_glyphs", "[I"), 0);
     CHECK_NULL_RETURN(gvdPositionsFID = (*env)->GetFieldID(env, gvdClass, "_positions", "[F"), 0);
     CHECK_NULL_RETURN(gvdIndicesFID = (*env)->GetFieldID(env, gvdClass, "_indices", "[I"), 0);
+    CHECK_NULL_RETURN(gvdGrowMID = (*env)->GetMethodID(env, gvdClass, "grow", "()V"), 0);
     jniInited = 1;
     return jniInited;
 }
 
 // gmask is the composite font slot mask
 // baseindex is to be added to the character (code point) index.
-int storeGVData(JNIEnv* env,
-               jobject gvdata, jint slot, jint baseIndex, jobject startPt,
-               int glyphCount, hb_glyph_info_t *glyphInfo,
-               hb_glyph_position_t *glyphPos, hb_direction_t direction,
-               float devScale) {
+jboolean storeGVData(JNIEnv* env,
+                     jobject gvdata, jint slot,
+                     jint baseIndex, int offset, jobject startPt,
+                     int charCount, int glyphCount, hb_glyph_info_t *glyphInfo,
+                     hb_glyph_position_t *glyphPos, float devScale) {
 
-    int i;
+    int i, needToGrow;
     float x=0, y=0;
-    float startX, startY;
+    float startX, startY, advX, advY;
     float scale = 1.0f / FloatToFixedScale / devScale;
     unsigned int* glyphs;
     float* positions;
-    int initialCount, glyphArrayLen, posArrayLen, maxGlyphs, storeadv;
+    int initialCount, glyphArrayLen, posArrayLen, maxGlyphs, storeadv, maxStore;
     unsigned int* indices;
     jarray glyphArray, posArray, inxArray;
 
     if (!init_JNI_IDs(env)) {
-        return 0;
+        return JNI_FALSE;
     }
 
     initialCount = (*env)->GetIntField(env, gvdata, gvdCountFID);
-    glyphArray =
-       (jarray)(*env)->GetObjectField(env, gvdata, gvdGlyphsFID);
-    posArray =
-        (jarray)(*env)->GetObjectField(env, gvdata, gvdPositionsFID);
-
-    if (glyphArray == NULL || posArray == NULL)
-    {
-        JNU_ThrowArrayIndexOutOfBoundsException(env, "");
-        return 0;
-    }
-
-    // The Java code catches the IIOBE and expands the storage
-    // and re-invokes layout. I suppose this is expected to be rare
-    // because at least in a single threaded case there should be
-    // re-use of the same container, but it is a little wasteful/distateful.
-    glyphArrayLen = (*env)->GetArrayLength(env, glyphArray);
-    posArrayLen = (*env)->GetArrayLength(env, posArray);
-    maxGlyphs = glyphCount + initialCount;
-    if ((maxGlyphs >  glyphArrayLen) ||
-        (maxGlyphs * 2 + 2 >  posArrayLen))
-    {
-        JNU_ThrowArrayIndexOutOfBoundsException(env, "");
-        return 0;
-    }
+    do {
+        glyphArray = (jarray)(*env)->GetObjectField(env, gvdata, gvdGlyphsFID);
+        posArray = (jarray)(*env)->GetObjectField(env, gvdata, gvdPositionsFID);
+        inxArray = (jarray)(*env)->GetObjectField(env, gvdata, gvdIndicesFID);
+        if (glyphArray == NULL || posArray == NULL || inxArray == NULL) {
+            JNU_ThrowArrayIndexOutOfBoundsException(env, "");
+            return JNI_FALSE;
+        }
+        glyphArrayLen = (*env)->GetArrayLength(env, glyphArray);
+        posArrayLen = (*env)->GetArrayLength(env, posArray);
+        maxGlyphs = (charCount > glyphCount) ? charCount : glyphCount;
+        maxStore = maxGlyphs + initialCount;
+        needToGrow = (maxStore > glyphArrayLen) ||
+                     (maxStore * 2 + 2 >  posArrayLen);
+        if (needToGrow) {
+            (*env)->CallVoidMethod(env, gvdata, gvdGrowMID);
+            if ((*env)->ExceptionCheck(env)) {
+                return JNI_FALSE;
+            }
+        }
+    } while (needToGrow);
 
     getFloat(env, startPt, &startX, &startY);
 
     glyphs =
         (unsigned int*)(*env)->GetPrimitiveArrayCritical(env, glyphArray, NULL);
+    if (glyphs == NULL) {
+        return JNI_FALSE;
+    }
     positions = (jfloat*)(*env)->GetPrimitiveArrayCritical(env, posArray, NULL);
+    if (positions == NULL) {
+        (*env)->ReleasePrimitiveArrayCritical(env, glyphArray, glyphs, 0);
+        return JNI_FALSE;
+    }
+    indices =
+        (unsigned int*)(*env)->GetPrimitiveArrayCritical(env, inxArray, NULL);
+    if (indices == NULL) {
+        (*env)->ReleasePrimitiveArrayCritical(env, glyphArray, glyphs, 0);
+        (*env)->ReleasePrimitiveArrayCritical(env, posArray, positions, 0);
+        return JNI_FALSE;
+    }
+
     for (i = 0; i < glyphCount; i++) {
         int storei = i + initialCount;
-        int index = glyphInfo[i].codepoint | slot;
-        if (i<glyphCount)glyphs[storei] = (unsigned int)index;
-        positions[(storei*2)] = startX + x + glyphPos[i].x_offset * scale;
-        positions[(storei*2)+1] = startY + y - glyphPos[i].y_offset * scale;
+        int cluster = glyphInfo[i].cluster - offset;
+        indices[storei] = baseIndex + cluster;
+        glyphs[storei] = (unsigned int)(glyphInfo[i].codepoint | slot);
+        positions[storei*2] = startX + x + glyphPos[i].x_offset * scale;
+        positions[(storei*2)+1] = startY + y + glyphPos[i].y_offset * scale;
         x += glyphPos[i].x_advance * scale;
         y += glyphPos[i].y_advance * scale;
+        storei++;
     }
-    storeadv = initialCount+glyphCount;
+    storeadv = initialCount + glyphCount;
     // The final slot in the positions array is important
     // because when the GlyphVector is created from this
     // data it determines the overall advance of the glyphvector
@@ -137,30 +153,17 @@
     // during rendering where text is broken into runs.
     // We also need to report it back into "pt", so layout can
     // pass it back down for that next run in this code.
-    positions[(storeadv*2)] = startX + x;
-    positions[(storeadv*2)+1] = startY + y;
+    advX = startX + x;
+    advY = startY + y;
+    positions[(storeadv*2)] = advX;
+    positions[(storeadv*2)+1] = advY;
     (*env)->ReleasePrimitiveArrayCritical(env, glyphArray, glyphs, 0);
     (*env)->ReleasePrimitiveArrayCritical(env, posArray, positions, 0);
-    putFloat(env, startPt,positions[(storeadv*2)],positions[(storeadv*2)+1] );
-    inxArray =
-        (jarray)(*env)->GetObjectField(env, gvdata, gvdIndicesFID);
-    indices =
-        (unsigned int*)(*env)->GetPrimitiveArrayCritical(env, inxArray, NULL);
-    for (i = 0; i < glyphCount; i++) {
-        int cluster = glyphInfo[i].cluster;
-        if (direction == HB_DIRECTION_LTR) {
-            // I need to understand what hb does when processing a substring
-            // I expected the cluster index to be from the start of the text
-            // to process.
-            // Instead it appears to be from the start of the whole thing.
-            indices[i+initialCount] = cluster;
-        } else {
-            indices[i+initialCount] = baseIndex + glyphCount -1 -i;
-        }
-    }
     (*env)->ReleasePrimitiveArrayCritical(env, inxArray, indices, 0);
-    (*env)->SetIntField(env, gvdata, gvdCountFID, initialCount+glyphCount);
-    return initialCount+glyphCount;
+    putFloat(env, startPt, advX, advY);
+    (*env)->SetIntField(env, gvdata, gvdCountFID, storeadv);
+
+    return JNI_TRUE;
 }
 
 static float euclidianDistance(float a, float b)
@@ -226,7 +229,9 @@
 }
 
 
-#define TYPO_RTL 0x80000000
+#define TYPO_KERN 0x00000001
+#define TYPO_LIGA 0x00000002
+#define TYPO_RTL  0x80000000
 
 JNIEXPORT jboolean JNICALL Java_sun_font_SunLayoutEngine_shape
     (JNIEnv *env, jclass cls,
@@ -255,10 +260,11 @@
      hb_glyph_info_t *glyphInfo;
      hb_glyph_position_t *glyphPos;
      hb_direction_t direction = HB_DIRECTION_LTR;
-     hb_feature_t *features =  NULL;
+     hb_feature_t *features = NULL;
      int featureCount = 0;
-
-     int i;
+     char* kern = (flags & TYPO_KERN) ? "kern" : "-kern";
+     char* liga = (flags & TYPO_LIGA) ? "liga" : "-liga";
+     jboolean ret;
      unsigned int buflen;
 
      JDKFontInfo *jdkFontInfo =
@@ -281,6 +287,8 @@
          direction = HB_DIRECTION_RTL;
      }
      hb_buffer_set_direction(buffer, direction);
+     hb_buffer_set_cluster_level(buffer,
+                                 HB_BUFFER_CLUSTER_LEVEL_MONOTONE_CHARACTERS);
 
      chars = (*env)->GetCharArrayElements(env, text, NULL);
      if ((*env)->ExceptionCheck(env)) {
@@ -293,36 +301,26 @@
 
      hb_buffer_add_utf16(buffer, chars, len, offset, limit-offset);
 
+     features = calloc(2, sizeof(hb_feature_t));
+     if (features) {
+         hb_feature_from_string(kern, -1, &features[featureCount++]);
+         hb_feature_from_string(liga, -1, &features[featureCount++]);
+     }
+
      hb_shape_full(hbfont, buffer, features, featureCount, 0);
      glyphCount = hb_buffer_get_length(buffer);
      glyphInfo = hb_buffer_get_glyph_infos(buffer, 0);
      glyphPos = hb_buffer_get_glyph_positions(buffer, &buflen);
-     for (i = 0; i < glyphCount; i++) {
-         int index = glyphInfo[i].codepoint;
-         int xadv = (glyphPos[i].x_advance);
-         int yadv = (glyphPos[i].y_advance);
-     }
-     // On "input" HB assigns a cluster index to each character in UTF-16.
-     // On output where a sequence of characters have been mapped to
-     // a glyph they are all mapped to the cluster index of the first character.
-     // The next cluster index will be that of the first character in the
-     // next cluster. So cluster indexes may 'skip' on output.
-     // This can also happen if there are supplementary code-points
-     // such that two UTF-16 characters are needed to make one codepoint.
-     // In RTL text you need to count down.
-     // So the following code tries to build the reverse map as expected
-     // by calling code.
 
-     storeGVData(env, gvdata, slot, baseIndex, startPt,
-                 glyphCount, glyphInfo, glyphPos, direction,
-                 jdkFontInfo->devScale);
+     ret = storeGVData(env, gvdata, slot, baseIndex, offset, startPt,
+                       limit - offset, glyphCount, glyphInfo, glyphPos,
+                       jdkFontInfo->devScale);
 
      hb_buffer_destroy (buffer);
      hb_font_destroy(hbfont);
      free((void*)jdkFontInfo);
      if (features != NULL) free(features);
      (*env)->ReleaseCharArrayElements(env, text, chars, JNI_ABORT);
-
-     return JNI_TRUE;
+     return ret;
 }