Path: blob/master/src/java.desktop/share/native/libfontmanager/HBShaper.c
41152 views
/*1* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.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 it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* 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 WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 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 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425#include <jni_util.h>26#include <stdlib.h>27#include "hb.h"28#include "hb-jdk.h"29#include "hb-ot.h"30#include "scriptMapping.h"3132static jclass gvdClass = 0;33static const char* gvdClassName = "sun/font/GlyphLayout$GVData";34static jfieldID gvdCountFID = 0;35static jfieldID gvdFlagsFID = 0;36static jfieldID gvdGlyphsFID = 0;37static jfieldID gvdPositionsFID = 0;38static jfieldID gvdIndicesFID = 0;39static jmethodID gvdGrowMID = 0;40static int jniInited = 0;4142static void getFloat(JNIEnv* env, jobject pt, jfloat *x, jfloat *y) {43*x = (*env)->GetFloatField(env, pt, sunFontIDs.xFID);44*y = (*env)->GetFloatField(env, pt, sunFontIDs.yFID);45}4647static void putFloat(JNIEnv* env, jobject pt, jfloat x, jfloat y) {48(*env)->SetFloatField(env, pt, sunFontIDs.xFID, x);49(*env)->SetFloatField(env, pt, sunFontIDs.yFID, y);50}5152static int init_JNI_IDs(JNIEnv *env) {53if (jniInited) {54return jniInited;55}56CHECK_NULL_RETURN(gvdClass = (*env)->FindClass(env, gvdClassName), 0);57CHECK_NULL_RETURN(gvdClass = (jclass)(*env)->NewGlobalRef(env, gvdClass), 0);58CHECK_NULL_RETURN(gvdCountFID = (*env)->GetFieldID(env, gvdClass, "_count", "I"), 0);59CHECK_NULL_RETURN(gvdFlagsFID = (*env)->GetFieldID(env, gvdClass, "_flags", "I"), 0);60CHECK_NULL_RETURN(gvdGlyphsFID = (*env)->GetFieldID(env, gvdClass, "_glyphs", "[I"), 0);61CHECK_NULL_RETURN(gvdPositionsFID = (*env)->GetFieldID(env, gvdClass, "_positions", "[F"), 0);62CHECK_NULL_RETURN(gvdIndicesFID = (*env)->GetFieldID(env, gvdClass, "_indices", "[I"), 0);63CHECK_NULL_RETURN(gvdGrowMID = (*env)->GetMethodID(env, gvdClass, "grow", "()V"), 0);64jniInited = 1;65return jniInited;66}6768// gmask is the composite font slot mask69// baseindex is to be added to the character (code point) index.70jboolean storeGVData(JNIEnv* env,71jobject gvdata, jint slot,72jint baseIndex, int offset, jobject startPt,73int charCount, int glyphCount, hb_glyph_info_t *glyphInfo,74hb_glyph_position_t *glyphPos, float devScale) {7576int i, needToGrow;77float x=0, y=0;78float startX, startY, advX, advY;79float scale = 1.0f / HBFloatToFixedScale / devScale;80unsigned int* glyphs;81float* positions;82int initialCount, glyphArrayLen, posArrayLen, maxGlyphs, storeadv, maxStore;83unsigned int* indices;84jarray glyphArray, posArray, inxArray;8586if (!init_JNI_IDs(env)) {87return JNI_FALSE;88}8990initialCount = (*env)->GetIntField(env, gvdata, gvdCountFID);91do {92glyphArray = (jarray)(*env)->GetObjectField(env, gvdata, gvdGlyphsFID);93posArray = (jarray)(*env)->GetObjectField(env, gvdata, gvdPositionsFID);94inxArray = (jarray)(*env)->GetObjectField(env, gvdata, gvdIndicesFID);95if (glyphArray == NULL || posArray == NULL || inxArray == NULL) {96JNU_ThrowArrayIndexOutOfBoundsException(env, "");97return JNI_FALSE;98}99glyphArrayLen = (*env)->GetArrayLength(env, glyphArray);100posArrayLen = (*env)->GetArrayLength(env, posArray);101maxGlyphs = (charCount > glyphCount) ? charCount : glyphCount;102maxStore = maxGlyphs + initialCount;103needToGrow = (maxStore > glyphArrayLen) ||104(maxStore * 2 + 2 > posArrayLen);105if (needToGrow) {106(*env)->CallVoidMethod(env, gvdata, gvdGrowMID);107if ((*env)->ExceptionCheck(env)) {108return JNI_FALSE;109}110}111} while (needToGrow);112113getFloat(env, startPt, &startX, &startY);114115glyphs =116(unsigned int*)(*env)->GetPrimitiveArrayCritical(env, glyphArray, NULL);117if (glyphs == NULL) {118return JNI_FALSE;119}120positions = (jfloat*)(*env)->GetPrimitiveArrayCritical(env, posArray, NULL);121if (positions == NULL) {122(*env)->ReleasePrimitiveArrayCritical(env, glyphArray, glyphs, 0);123return JNI_FALSE;124}125indices =126(unsigned int*)(*env)->GetPrimitiveArrayCritical(env, inxArray, NULL);127if (indices == NULL) {128(*env)->ReleasePrimitiveArrayCritical(env, glyphArray, glyphs, 0);129(*env)->ReleasePrimitiveArrayCritical(env, posArray, positions, 0);130return JNI_FALSE;131}132133for (i = 0; i < glyphCount; i++) {134int storei = i + initialCount;135int cluster = glyphInfo[i].cluster - offset;136indices[storei] = baseIndex + cluster;137glyphs[storei] = (unsigned int)(glyphInfo[i].codepoint | slot);138positions[storei*2] = startX + x + glyphPos[i].x_offset * scale;139positions[(storei*2)+1] = startY + y - glyphPos[i].y_offset * scale;140x += glyphPos[i].x_advance * scale;141y += glyphPos[i].y_advance * scale;142storei++;143}144storeadv = initialCount + glyphCount;145// The final slot in the positions array is important146// because when the GlyphVector is created from this147// data it determines the overall advance of the glyphvector148// and this is used in positioning the next glyphvector149// during rendering where text is broken into runs.150// We also need to report it back into "pt", so layout can151// pass it back down for that next run in this code.152advX = startX + x;153advY = startY + y;154positions[(storeadv*2)] = advX;155positions[(storeadv*2)+1] = advY;156(*env)->ReleasePrimitiveArrayCritical(env, glyphArray, glyphs, 0);157(*env)->ReleasePrimitiveArrayCritical(env, posArray, positions, 0);158(*env)->ReleasePrimitiveArrayCritical(env, inxArray, indices, 0);159putFloat(env, startPt, advX, advY);160(*env)->SetIntField(env, gvdata, gvdCountFID, storeadv);161162return JNI_TRUE;163}164165static float euclidianDistance(float a, float b)166{167float root;168if (a < 0) {169a = -a;170}171172if (b < 0) {173b = -b;174}175176if (a == 0) {177return b;178}179180if (b == 0) {181return a;182}183184/* Do an initial approximation, in root */185root = a > b ? a + (b / 2) : b + (a / 2);186187/* An unrolled Newton-Raphson iteration sequence */188root = (root + (a * (a / root)) + (b * (b / root)) + 1) / 2;189root = (root + (a * (a / root)) + (b * (b / root)) + 1) / 2;190root = (root + (a * (a / root)) + (b * (b / root)) + 1) / 2;191192return root;193}194195JDKFontInfo*196createJDKFontInfo(JNIEnv *env,197jobject font2D,198jobject fontStrike,199jfloat ptSize,200jfloatArray matrix) {201202203JDKFontInfo *fi = (JDKFontInfo*)malloc(sizeof(JDKFontInfo));204if (!fi) {205return NULL;206}207fi->env = env; // this is valid only for the life of this JNI call.208fi->font2D = font2D;209fi->fontStrike = fontStrike;210(*env)->GetFloatArrayRegion(env, matrix, 0, 4, fi->matrix);211fi->ptSize = ptSize;212fi->xPtSize = euclidianDistance(fi->matrix[0], fi->matrix[1]);213fi->yPtSize = euclidianDistance(fi->matrix[2], fi->matrix[3]);214if (getenv("HB_NODEVTX") != NULL) {215fi->devScale = fi->xPtSize / fi->ptSize;216} else {217fi->devScale = 1.0f;218}219return fi;220}221222223#define TYPO_KERN 0x00000001224#define TYPO_LIGA 0x00000002225#define TYPO_RTL 0x80000000226227JNIEXPORT jboolean JNICALL Java_sun_font_SunLayoutEngine_shape228(JNIEnv *env, jclass cls,229jobject font2D,230jobject fontStrike,231jfloat ptSize,232jfloatArray matrix,233jlong pFace,234jcharArray text,235jobject gvdata,236jint script,237jint offset,238jint limit,239jint baseIndex,240jobject startPt,241jint flags,242jint slot) {243244hb_buffer_t *buffer;245hb_face_t* hbface;246hb_font_t* hbfont;247jchar *chars;248jsize len;249int glyphCount;250hb_glyph_info_t *glyphInfo;251hb_glyph_position_t *glyphPos;252hb_direction_t direction = HB_DIRECTION_LTR;253hb_feature_t *features = NULL;254int featureCount = 0;255char* kern = (flags & TYPO_KERN) ? "kern" : "-kern";256char* liga = (flags & TYPO_LIGA) ? "liga" : "-liga";257jboolean ret;258unsigned int buflen;259260JDKFontInfo *jdkFontInfo =261createJDKFontInfo(env, font2D, fontStrike, ptSize, matrix);262if (!jdkFontInfo) {263return JNI_FALSE;264}265jdkFontInfo->env = env; // this is valid only for the life of this JNI call.266jdkFontInfo->font2D = font2D;267jdkFontInfo->fontStrike = fontStrike;268269hbface = (hb_face_t*) jlong_to_ptr(pFace);270hbfont = hb_jdk_font_create(hbface, jdkFontInfo, NULL);271272buffer = hb_buffer_create();273hb_buffer_set_script(buffer, getHBScriptCode(script));274hb_buffer_set_language(buffer,275hb_ot_tag_to_language(HB_OT_TAG_DEFAULT_LANGUAGE));276if ((flags & TYPO_RTL) != 0) {277direction = HB_DIRECTION_RTL;278}279hb_buffer_set_direction(buffer, direction);280hb_buffer_set_cluster_level(buffer,281HB_BUFFER_CLUSTER_LEVEL_MONOTONE_CHARACTERS);282283chars = (*env)->GetCharArrayElements(env, text, NULL);284if ((*env)->ExceptionCheck(env)) {285hb_buffer_destroy(buffer);286hb_font_destroy(hbfont);287free((void*)jdkFontInfo);288return JNI_FALSE;289}290len = (*env)->GetArrayLength(env, text);291292hb_buffer_add_utf16(buffer, chars, len, offset, limit-offset);293294features = calloc(2, sizeof(hb_feature_t));295if (features) {296hb_feature_from_string(kern, -1, &features[featureCount++]);297hb_feature_from_string(liga, -1, &features[featureCount++]);298}299300hb_shape_full(hbfont, buffer, features, featureCount, 0);301glyphCount = hb_buffer_get_length(buffer);302glyphInfo = hb_buffer_get_glyph_infos(buffer, 0);303glyphPos = hb_buffer_get_glyph_positions(buffer, &buflen);304305ret = storeGVData(env, gvdata, slot, baseIndex, offset, startPt,306limit - offset, glyphCount, glyphInfo, glyphPos,307jdkFontInfo->devScale);308309hb_buffer_destroy (buffer);310hb_font_destroy(hbfont);311free((void*)jdkFontInfo);312if (features != NULL) free(features);313(*env)->ReleaseCharArrayElements(env, text, chars, JNI_ABORT);314return ret;315}316317318319