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 if (count < 0) { 108 JNU_ThrowInternalError(env, "count negative"); 109 return 0; 110 } 111 112 jarray glyphArray = (jarray)env->GetObjectField(gvdata, gvdGlyphsFID); 113 if (IS_NULL(glyphArray)) { 114 JNU_ThrowInternalError(env, "glypharray null"); 115 return 0; 116 } 117 jint capacity = env->GetArrayLength(glyphArray); 118 if (count + glyphCount > capacity) { 119 JNU_ThrowArrayIndexOutOfBoundsException(env, ""); 120 return 0; 121 } 122 123 jarray posArray = (jarray)env->GetObjectField(gvdata, gvdPositionsFID); 124 if (IS_NULL(glyphArray)) { 125 JNU_ThrowInternalError(env, "positions array null"); 126 return 0; 127 } 128 jarray inxArray = (jarray)env->GetObjectField(gvdata, gvdIndicesFID); 129 if (IS_NULL(inxArray)) { 130 JNU_ThrowInternalError(env, "indices array null"); 131 return 0; 132 } 133 134 int countDelta = 0; 135 136 // le_uint32 is the same size as jint... forever, we hope 137 le_uint32* glyphs = (le_uint32*)env->GetPrimitiveArrayCritical(glyphArray, NULL); 138 if (glyphs) { 139 jfloat* positions = (jfloat*)env->GetPrimitiveArrayCritical(posArray, NULL); 140 if (positions) { 141 jint* indices = (jint*)env->GetPrimitiveArrayCritical(inxArray, NULL); 142 if (indices) { 143 LEErrorCode status = (LEErrorCode)0; 144 engine->getGlyphs(glyphs + count, gmask, status); 145 engine->getGlyphPositions(positions + (count * 2), status); 146 engine->getCharIndices((le_int32*)(indices + count), baseIndex, status); 147 148 countDelta = glyphCount; 149 150 // !!! need engine->getFlags to signal positions, indices data 151 /* "0" arg used instead of JNI_COMMIT as we want the carray 152 * to be freed by any VM that actually passes us a copy. 153 */ 154 env->ReleasePrimitiveArrayCritical(inxArray, indices, 0); 155 } 156 env->ReleasePrimitiveArrayCritical(posArray, positions, 0); 157 } 158 env->ReleasePrimitiveArrayCritical(glyphArray, glyphs, 0); 159 } 160 161 if (countDelta) { 162 count += countDelta; 163 env->SetIntField(gvdata, gvdCountFID, count); 164 } 165 166 return 1; 167 } 168 169 /* 170 * Class: sun_font_SunLayoutEngine 171 * Method: nativeLayout 172 * Signature: (Lsun/font/FontStrike;[CIIIIZLjava/awt/geom/Point2D$Float;Lsun/font/GlyphLayout$GVData;)V 173 */ 174 JNIEXPORT void JNICALL Java_sun_font_SunLayoutEngine_nativeLayout 175 (JNIEnv *env, jclass cls, jobject font2d, jobject strike, jfloatArray matrix, jint gmask, 176 jint baseIndex, jcharArray text, jint start, jint limit, jint min, jint max, 177 jint script, jint lang, jint typo_flags, jobject pt, jobject gvdata, 178 jlong upem, jlong layoutTables) 179 { 180 // fprintf(stderr, "nl font: %x strike: %x script: %d\n", font2d, strike, script); fflush(stderr); 181 float mat[4]; 182 env->GetFloatArrayRegion(matrix, 0, 4, mat); 183 FontInstanceAdapter fia(env, font2d, strike, mat, 72, 72, (le_int32) upem, (TTLayoutTableCache *) layoutTables); 184 LEErrorCode success = LE_NO_ERROR; 185 LayoutEngine *engine = LayoutEngine::layoutEngineFactory(&fia, script, lang, typo_flags & TYPO_MASK, success); 186 if (engine == NULL) { 187 env->SetIntField(gvdata, gvdCountFID, -1); // flag failure 188 return; 189 } 190 191 if (min < 0) min = 0; if (max < min) max = min; /* defensive coding */ 192 // have to copy, yuck, since code does upcalls now. this will be soooo slow 193 jint len = max - min; 194 jchar buffer[256]; 195 jchar* chars = buffer; 196 if (len > 256) { 197 size_t size = len * sizeof(jchar); 198 if (size / sizeof(jchar) != len) { 199 return; 200 } 201 chars = (jchar*)malloc(size); 202 if (chars == 0) { 203 return; 204 } 205 } 206 // fprintf(stderr, "nl chars: %x text: %x min %d len %d typo %x\n", chars, text, min, len, typo_flags); fflush(stderr); 207 208 env->GetCharArrayRegion(text, min, len, chars); 209 210 jfloat x, y; 211 getFloat(env, pt, x, y); 212 jboolean rtl = (typo_flags & TYPO_RTL) != 0; 213 int glyphCount = engine->layoutChars(chars, start - min, limit - start, len, rtl, x, y, success); 214 // fprintf(stderr, "sle nl len %d -> gc: %d\n", len, glyphCount); fflush(stderr); 215 216 engine->getGlyphPosition(glyphCount, x, y, success); 217 218 // fprintf(stderr, "layout glyphs: %d x: %g y: %g\n", glyphCount, x, y); fflush(stderr); 219 if (LE_FAILURE(success)) { 220 env->SetIntField(gvdata, gvdCountFID, -1); // flag failure 221 } else { 222 if (putGV(env, gmask, baseIndex, gvdata, engine, glyphCount)) { 223 // !!! hmmm, could use current value in positions array of GVData... 224 putFloat(env, pt, x, y); 225 } 226 } 227 228 if (chars != buffer) { 229 free(chars); 230 } 231 232 delete engine; 233 234 }