1 /*
   2  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   3  *
   4  * This code is free software; you can redistribute it and/or modify it
   5  * under the terms of the GNU General Public License version 2 only, as
   6  * published by the Free Software Foundation.  Oracle designates this
   7  * particular file as subject to the "Classpath" exception as provided
   8  * by Oracle in the LICENSE file that accompanied this code.
   9  *
  10  * This code is distributed in the hope that it will be useful, but WITHOUT
  11  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  12  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  13  * version 2 for more details (a copy is included in the LICENSE file that
  14  * accompanied this code).
  15  *
  16  * You should have received a copy of the GNU General Public License version
  17  * 2 along with this work; if not, write to the Free Software Foundation,
  18  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  19  *
  20  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  21  * or visit www.oracle.com if you need additional information or have any
  22  * questions.
  23  */
  24 
  25 /* Header for class sun_font_SunLayoutEngine */
  26 
  27 #include <jni_util.h>
  28 #include <stdlib.h>
  29 
  30 #include "FontInstanceAdapter.h"
  31 #include "LayoutEngine.h"
  32 #include "sun_font_SunLayoutEngine.h"
  33 #include "sunfontids.h"
  34 
  35 void getFloat(JNIEnv* env, jobject pt, jfloat &x, jfloat &y) {
  36     x = env->GetFloatField(pt, sunFontIDs.xFID);
  37     y = env->GetFloatField(pt, sunFontIDs.yFID);
  38 }
  39 
  40 void putFloat(JNIEnv* env, jobject pt, jfloat x, jfloat y) {
  41     env->SetFloatField(pt, sunFontIDs.xFID, x);
  42     env->SetFloatField(pt, sunFontIDs.yFID, y);
  43 }
  44 
  45 static jclass gvdClass = 0;
  46 static const char* gvdClassName = "sun/font/GlyphLayout$GVData";
  47 static jfieldID gvdCountFID = 0;
  48 static jfieldID gvdFlagsFID = 0;
  49 static jfieldID gvdGlyphsFID = 0;
  50 static jfieldID gvdPositionsFID = 0;
  51 static jfieldID gvdIndicesFID = 0;
  52 
  53 #define TYPO_RTL 0x80000000
  54 #define TYPO_MASK 0x7
  55 
  56 JNIEXPORT void JNICALL
  57 Java_sun_font_SunLayoutEngine_initGVIDs
  58     (JNIEnv *env, jclass cls) {
  59     gvdClass = env->FindClass(gvdClassName);
  60     if (!gvdClass) {
  61         JNU_ThrowClassNotFoundException(env, gvdClassName);
  62         return;
  63     }
  64     gvdClass = (jclass)env->NewGlobalRef(gvdClass);
  65       if (!gvdClass) {
  66         JNU_ThrowInternalError(env, "could not create global ref");
  67         return;
  68     }
  69     gvdCountFID = env->GetFieldID(gvdClass, "_count", "I");
  70     if (!gvdCountFID) {
  71       gvdClass = 0;
  72       JNU_ThrowNoSuchFieldException(env, "_count");
  73       return;
  74     }
  75 
  76     gvdFlagsFID = env->GetFieldID(gvdClass, "_flags", "I");
  77     if (!gvdFlagsFID) {
  78       gvdClass = 0;
  79       JNU_ThrowNoSuchFieldException(env, "_flags");
  80       return;
  81     }
  82 
  83     gvdGlyphsFID = env->GetFieldID(gvdClass, "_glyphs", "[I");
  84     if (!gvdGlyphsFID) {
  85       gvdClass = 0;
  86       JNU_ThrowNoSuchFieldException(env, "_glyphs");
  87       return;
  88     }
  89 
  90     gvdPositionsFID = env->GetFieldID(gvdClass, "_positions", "[F");
  91     if (!gvdPositionsFID) {
  92       gvdClass = 0;
  93       JNU_ThrowNoSuchFieldException(env, "_positions");
  94       return;
  95     }
  96 
  97     gvdIndicesFID = env->GetFieldID(gvdClass, "_indices", "[I");
  98     if (!gvdIndicesFID) {
  99       gvdClass = 0;
 100       JNU_ThrowNoSuchFieldException(env, "_indices");
 101       return;
 102     }
 103 }
 104 
 105 int putGV(JNIEnv* env, jint gmask, jint baseIndex, jobject gvdata, const LayoutEngine* engine, int glyphCount) {
 106     int count = env->GetIntField(gvdata, gvdCountFID);
 107 
 108     jarray glyphArray = (jarray)env->GetObjectField(gvdata, gvdGlyphsFID);
 109     if (IS_NULL(glyphArray)) {
 110       JNU_ThrowInternalError(env, "glypharray null");
 111       return 0;
 112     }
 113     jint capacity = env->GetArrayLength(glyphArray);
 114     if (count + glyphCount > capacity) {
 115       JNU_ThrowArrayIndexOutOfBoundsException(env, "");
 116       return 0;
 117     }
 118 
 119     jarray posArray = (jarray)env->GetObjectField(gvdata, gvdPositionsFID);
 120     if (IS_NULL(glyphArray)) {
 121       JNU_ThrowInternalError(env, "positions array null");
 122       return 0;
 123     }
 124     jarray inxArray = (jarray)env->GetObjectField(gvdata, gvdIndicesFID);
 125     if (IS_NULL(inxArray)) {
 126       JNU_ThrowInternalError(env, "indices array null");
 127       return 0;
 128     }
 129 
 130     int countDelta = 0;
 131 
 132     // le_uint32 is the same size as jint... forever, we hope
 133     le_uint32* glyphs = (le_uint32*)env->GetPrimitiveArrayCritical(glyphArray, NULL);
 134     if (glyphs) {
 135       jfloat* positions = (jfloat*)env->GetPrimitiveArrayCritical(posArray, NULL);
 136       if (positions) {
 137         jint* indices = (jint*)env->GetPrimitiveArrayCritical(inxArray, NULL);
 138         if (indices) {
 139           LEErrorCode status = (LEErrorCode)0;
 140           engine->getGlyphs(glyphs + count, gmask, status);
 141           engine->getGlyphPositions(positions + (count * 2), status);
 142           engine->getCharIndices((le_int32*)(indices + count), baseIndex, status);
 143 
 144           countDelta = glyphCount;
 145 
 146           // !!! need engine->getFlags to signal positions, indices data
 147           /* "0" arg used instead of JNI_COMMIT as we want the carray
 148            * to be freed by any VM that actually passes us a copy.
 149            */
 150           env->ReleasePrimitiveArrayCritical(inxArray, indices, 0);
 151         }
 152         env->ReleasePrimitiveArrayCritical(posArray, positions, 0);
 153       }
 154       env->ReleasePrimitiveArrayCritical(glyphArray, glyphs, 0);
 155     }
 156 
 157     if (countDelta) {
 158       count += countDelta;
 159       env->SetIntField(gvdata, gvdCountFID, count);
 160     }
 161 
 162   return 1;
 163 }
 164 
 165 /*
 166  * Class:     sun_font_SunLayoutEngine
 167  * Method:    nativeLayout
 168  * Signature: (Lsun/font/FontStrike;[CIIIIZLjava/awt/geom/Point2D$Float;Lsun/font/GlyphLayout$GVData;)V
 169  */
 170 JNIEXPORT void JNICALL Java_sun_font_SunLayoutEngine_nativeLayout
 171    (JNIEnv *env, jclass cls, jobject font2d, jobject strike, jfloatArray matrix, jint gmask,
 172    jint baseIndex, jcharArray text, jint start, jint limit, jint min, jint max,
 173    jint script, jint lang, jint typo_flags, jobject pt, jobject gvdata,
 174    jlong upem, jlong layoutTables)
 175 {
 176     //  fprintf(stderr, "nl font: %x strike: %x script: %d\n", font2d, strike, script); fflush(stderr);
 177   float mat[4];
 178   env->GetFloatArrayRegion(matrix, 0, 4, mat);
 179   FontInstanceAdapter fia(env, font2d, strike, mat, 72, 72, (le_int32) upem, (TTLayoutTableCache *) layoutTables);
 180   LEErrorCode success = LE_NO_ERROR;
 181   LayoutEngine *engine = LayoutEngine::layoutEngineFactory(&fia, script, lang, typo_flags & TYPO_MASK, success);
 182 
 183   if (min < 0) min = 0; if (max < min) max = min; /* defensive coding */
 184   // have to copy, yuck, since code does upcalls now.  this will be soooo slow
 185   jint len = max - min;
 186   jchar buffer[256];
 187   jchar* chars = buffer;
 188   if (len > 256) {
 189     size_t size = len * sizeof(jchar);
 190     if (size / sizeof(jchar) != len) {
 191       return;
 192     }
 193     chars = (jchar*)malloc(size);
 194     if (chars == 0) {
 195       return;
 196     }
 197   }
 198   //  fprintf(stderr, "nl chars: %x text: %x min %d len %d typo %x\n", chars, text, min, len, typo_flags); fflush(stderr);
 199 
 200   env->GetCharArrayRegion(text, min, len, chars);
 201 
 202   jfloat x, y;
 203   getFloat(env, pt, x, y);
 204   jboolean rtl = (typo_flags & TYPO_RTL) != 0;
 205   int glyphCount = engine->layoutChars(chars, start - min, limit - start, len, rtl, x, y, success);
 206   //   fprintf(stderr, "sle nl len %d -> gc: %d\n", len, glyphCount); fflush(stderr);
 207 
 208   engine->getGlyphPosition(glyphCount, x, y, success);
 209 
 210   //  fprintf(stderr, "layout glyphs: %d x: %g y: %g\n", glyphCount, x, y); fflush(stderr);
 211 
 212   if (putGV(env, gmask, baseIndex, gvdata, engine, glyphCount)) {
 213     // !!! hmmm, could use current value in positions array of GVData...
 214     putFloat(env, pt, x, y);
 215   }
 216 
 217   if (chars != buffer) {
 218     free(chars);
 219   }
 220 
 221   delete engine;
 222 
 223 }