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     CHECK_NULL(gvdClass = env->FindClass(gvdClassName));
  60     CHECK_NULL(gvdClass = (jclass)env->NewGlobalRef(gvdClass));
  61     CHECK_NULL(gvdCountFID = env->GetFieldID(gvdClass, "_count", "I"));
  62     CHECK_NULL(gvdFlagsFID = env->GetFieldID(gvdClass, "_flags", "I"));
  63     CHECK_NULL(gvdGlyphsFID = env->GetFieldID(gvdClass, "_glyphs", "[I"));
  64     CHECK_NULL(gvdPositionsFID = env->GetFieldID(gvdClass, "_positions", "[F"));
  65     gvdIndicesFID = env->GetFieldID(gvdClass, "_indices", "[I");
  66 }
  67 
  68 int putGV(JNIEnv* env, jint gmask, jint baseIndex, jobject gvdata, const LayoutEngine* engine, int glyphCount) {
  69     int count = env->GetIntField(gvdata, gvdCountFID);
  70     if (count < 0) {
  71       JNU_ThrowInternalError(env, "count negative");
  72       return 0;
  73     }
  74 
  75     jarray glyphArray = (jarray)env->GetObjectField(gvdata, gvdGlyphsFID);
  76     if (IS_NULL(glyphArray)) {
  77       JNU_ThrowInternalError(env, "glypharray null");
  78       return 0;
  79     }
  80     jint capacity = env->GetArrayLength(glyphArray);
  81     if (count + glyphCount > capacity) {
  82       JNU_ThrowArrayIndexOutOfBoundsException(env, "");
  83       return 0;
  84     }
  85 
  86     jarray posArray = (jarray)env->GetObjectField(gvdata, gvdPositionsFID);
  87     if (IS_NULL(glyphArray)) {
  88       JNU_ThrowInternalError(env, "positions array null");
  89       return 0;
  90     }
  91     jarray inxArray = (jarray)env->GetObjectField(gvdata, gvdIndicesFID);
  92     if (IS_NULL(inxArray)) {
  93       JNU_ThrowInternalError(env, "indices array null");
  94       return 0;
  95     }
  96 
  97     int countDelta = 0;
  98 
  99     // le_uint32 is the same size as jint... forever, we hope
 100     le_uint32* glyphs = (le_uint32*)env->GetPrimitiveArrayCritical(glyphArray, NULL);
 101     if (glyphs) {
 102       jfloat* positions = (jfloat*)env->GetPrimitiveArrayCritical(posArray, NULL);
 103       if (positions) {
 104         jint* indices = (jint*)env->GetPrimitiveArrayCritical(inxArray, NULL);
 105         if (indices) {
 106           LEErrorCode status = (LEErrorCode)0;
 107           engine->getGlyphs(glyphs + count, gmask, status);
 108           engine->getGlyphPositions(positions + (count * 2), status);
 109           engine->getCharIndices((le_int32*)(indices + count), baseIndex, status);
 110 
 111           countDelta = glyphCount;
 112 
 113           // !!! need engine->getFlags to signal positions, indices data
 114           /* "0" arg used instead of JNI_COMMIT as we want the carray
 115            * to be freed by any VM that actually passes us a copy.
 116            */
 117           env->ReleasePrimitiveArrayCritical(inxArray, indices, 0);
 118         }
 119         env->ReleasePrimitiveArrayCritical(posArray, positions, 0);
 120       }
 121       env->ReleasePrimitiveArrayCritical(glyphArray, glyphs, 0);
 122     }
 123 
 124     if (countDelta) {
 125       count += countDelta;
 126       env->SetIntField(gvdata, gvdCountFID, count);
 127     }
 128 
 129   return 1;
 130 }
 131 
 132 /*
 133  * Class:     sun_font_SunLayoutEngine
 134  * Method:    nativeLayout
 135  * Signature: (Lsun/font/FontStrike;[CIIIIZLjava/awt/geom/Point2D$Float;Lsun/font/GlyphLayout$GVData;)V
 136  */
 137 JNIEXPORT void JNICALL Java_sun_font_SunLayoutEngine_nativeLayout
 138    (JNIEnv *env, jclass cls, jobject font2d, jobject strike, jfloatArray matrix, jint gmask,
 139    jint baseIndex, jcharArray text, jint start, jint limit, jint min, jint max,
 140    jint script, jint lang, jint typo_flags, jobject pt, jobject gvdata,
 141    jlong upem, jlong layoutTables)
 142 {
 143     //  fprintf(stderr, "nl font: %x strike: %x script: %d\n", font2d, strike, script); fflush(stderr);
 144   float mat[4];
 145   env->GetFloatArrayRegion(matrix, 0, 4, mat);
 146   FontInstanceAdapter fia(env, font2d, strike, mat, 72, 72, (le_int32) upem, (TTLayoutTableCache *) layoutTables);
 147   LEErrorCode success = LE_NO_ERROR;
 148   LayoutEngine *engine = LayoutEngine::layoutEngineFactory(&fia, script, lang, typo_flags & TYPO_MASK, success);
 149   if (engine == NULL) {
 150     env->SetIntField(gvdata, gvdCountFID, -1); // flag failure
 151     return;
 152   }
 153 
 154   if (min < 0) min = 0; if (max < min) max = min; /* defensive coding */
 155   // have to copy, yuck, since code does upcalls now.  this will be soooo slow
 156   jint len = max - min;
 157   jchar buffer[256];
 158   jchar* chars = buffer;
 159   if (len > 256) {
 160     size_t size = len * sizeof(jchar);
 161     if (size / sizeof(jchar) != (size_t)len) {
 162       return;
 163     }
 164     chars = (jchar*)malloc(size);
 165     if (chars == 0) {
 166       return;
 167     }
 168   }
 169   //  fprintf(stderr, "nl chars: %x text: %x min %d len %d typo %x\n", chars, text, min, len, typo_flags); fflush(stderr);
 170 
 171   env->GetCharArrayRegion(text, min, len, chars);
 172 
 173   jfloat x, y;
 174   getFloat(env, pt, x, y);
 175   jboolean rtl = (typo_flags & TYPO_RTL) != 0;
 176   int glyphCount = engine->layoutChars(chars, start - min, limit - start, len, rtl, x, y, success);
 177     // fprintf(stderr, "sle nl len %d -> gc: %d\n", len, glyphCount); fflush(stderr);
 178 
 179   engine->getGlyphPosition(glyphCount, x, y, success);
 180 
 181    // fprintf(stderr, "layout glyphs: %d x: %g y: %g\n", glyphCount, x, y); fflush(stderr);
 182    if (LE_FAILURE(success)) {
 183        env->SetIntField(gvdata, gvdCountFID, -1); // flag failure
 184    } else {
 185       if (putGV(env, gmask, baseIndex, gvdata, engine, glyphCount)) {
 186           if (!(env->ExceptionCheck())) {
 187         // !!! hmmm, could use current value in positions array of GVData...
 188         putFloat(env, pt, x, y);
 189       }
 190    }
 191    }
 192 
 193   if (chars != buffer) {
 194     free(chars);
 195   }
 196 
 197   delete engine;
 198 
 199 }