Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/src/java.desktop/share/native/libfontmanager/HBShaper.c
41152 views
1
/*
2
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
3
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4
*
5
* This code is free software; you can redistribute it and/or modify it
6
* under the terms of the GNU General Public License version 2 only, as
7
* published by the Free Software Foundation. Oracle designates this
8
* particular file as subject to the "Classpath" exception as provided
9
* by Oracle in the LICENSE file that accompanied this code.
10
*
11
* This code is distributed in the hope that it will be useful, but WITHOUT
12
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14
* version 2 for more details (a copy is included in the LICENSE file that
15
* accompanied this code).
16
*
17
* You should have received a copy of the GNU General Public License version
18
* 2 along with this work; if not, write to the Free Software Foundation,
19
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20
*
21
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22
* or visit www.oracle.com if you need additional information or have any
23
* questions.
24
*/
25
26
#include <jni_util.h>
27
#include <stdlib.h>
28
#include "hb.h"
29
#include "hb-jdk.h"
30
#include "hb-ot.h"
31
#include "scriptMapping.h"
32
33
static jclass gvdClass = 0;
34
static const char* gvdClassName = "sun/font/GlyphLayout$GVData";
35
static jfieldID gvdCountFID = 0;
36
static jfieldID gvdFlagsFID = 0;
37
static jfieldID gvdGlyphsFID = 0;
38
static jfieldID gvdPositionsFID = 0;
39
static jfieldID gvdIndicesFID = 0;
40
static jmethodID gvdGrowMID = 0;
41
static int jniInited = 0;
42
43
static void getFloat(JNIEnv* env, jobject pt, jfloat *x, jfloat *y) {
44
*x = (*env)->GetFloatField(env, pt, sunFontIDs.xFID);
45
*y = (*env)->GetFloatField(env, pt, sunFontIDs.yFID);
46
}
47
48
static void putFloat(JNIEnv* env, jobject pt, jfloat x, jfloat y) {
49
(*env)->SetFloatField(env, pt, sunFontIDs.xFID, x);
50
(*env)->SetFloatField(env, pt, sunFontIDs.yFID, y);
51
}
52
53
static int init_JNI_IDs(JNIEnv *env) {
54
if (jniInited) {
55
return jniInited;
56
}
57
CHECK_NULL_RETURN(gvdClass = (*env)->FindClass(env, gvdClassName), 0);
58
CHECK_NULL_RETURN(gvdClass = (jclass)(*env)->NewGlobalRef(env, gvdClass), 0);
59
CHECK_NULL_RETURN(gvdCountFID = (*env)->GetFieldID(env, gvdClass, "_count", "I"), 0);
60
CHECK_NULL_RETURN(gvdFlagsFID = (*env)->GetFieldID(env, gvdClass, "_flags", "I"), 0);
61
CHECK_NULL_RETURN(gvdGlyphsFID = (*env)->GetFieldID(env, gvdClass, "_glyphs", "[I"), 0);
62
CHECK_NULL_RETURN(gvdPositionsFID = (*env)->GetFieldID(env, gvdClass, "_positions", "[F"), 0);
63
CHECK_NULL_RETURN(gvdIndicesFID = (*env)->GetFieldID(env, gvdClass, "_indices", "[I"), 0);
64
CHECK_NULL_RETURN(gvdGrowMID = (*env)->GetMethodID(env, gvdClass, "grow", "()V"), 0);
65
jniInited = 1;
66
return jniInited;
67
}
68
69
// gmask is the composite font slot mask
70
// baseindex is to be added to the character (code point) index.
71
jboolean storeGVData(JNIEnv* env,
72
jobject gvdata, jint slot,
73
jint baseIndex, int offset, jobject startPt,
74
int charCount, int glyphCount, hb_glyph_info_t *glyphInfo,
75
hb_glyph_position_t *glyphPos, float devScale) {
76
77
int i, needToGrow;
78
float x=0, y=0;
79
float startX, startY, advX, advY;
80
float scale = 1.0f / HBFloatToFixedScale / devScale;
81
unsigned int* glyphs;
82
float* positions;
83
int initialCount, glyphArrayLen, posArrayLen, maxGlyphs, storeadv, maxStore;
84
unsigned int* indices;
85
jarray glyphArray, posArray, inxArray;
86
87
if (!init_JNI_IDs(env)) {
88
return JNI_FALSE;
89
}
90
91
initialCount = (*env)->GetIntField(env, gvdata, gvdCountFID);
92
do {
93
glyphArray = (jarray)(*env)->GetObjectField(env, gvdata, gvdGlyphsFID);
94
posArray = (jarray)(*env)->GetObjectField(env, gvdata, gvdPositionsFID);
95
inxArray = (jarray)(*env)->GetObjectField(env, gvdata, gvdIndicesFID);
96
if (glyphArray == NULL || posArray == NULL || inxArray == NULL) {
97
JNU_ThrowArrayIndexOutOfBoundsException(env, "");
98
return JNI_FALSE;
99
}
100
glyphArrayLen = (*env)->GetArrayLength(env, glyphArray);
101
posArrayLen = (*env)->GetArrayLength(env, posArray);
102
maxGlyphs = (charCount > glyphCount) ? charCount : glyphCount;
103
maxStore = maxGlyphs + initialCount;
104
needToGrow = (maxStore > glyphArrayLen) ||
105
(maxStore * 2 + 2 > posArrayLen);
106
if (needToGrow) {
107
(*env)->CallVoidMethod(env, gvdata, gvdGrowMID);
108
if ((*env)->ExceptionCheck(env)) {
109
return JNI_FALSE;
110
}
111
}
112
} while (needToGrow);
113
114
getFloat(env, startPt, &startX, &startY);
115
116
glyphs =
117
(unsigned int*)(*env)->GetPrimitiveArrayCritical(env, glyphArray, NULL);
118
if (glyphs == NULL) {
119
return JNI_FALSE;
120
}
121
positions = (jfloat*)(*env)->GetPrimitiveArrayCritical(env, posArray, NULL);
122
if (positions == NULL) {
123
(*env)->ReleasePrimitiveArrayCritical(env, glyphArray, glyphs, 0);
124
return JNI_FALSE;
125
}
126
indices =
127
(unsigned int*)(*env)->GetPrimitiveArrayCritical(env, inxArray, NULL);
128
if (indices == NULL) {
129
(*env)->ReleasePrimitiveArrayCritical(env, glyphArray, glyphs, 0);
130
(*env)->ReleasePrimitiveArrayCritical(env, posArray, positions, 0);
131
return JNI_FALSE;
132
}
133
134
for (i = 0; i < glyphCount; i++) {
135
int storei = i + initialCount;
136
int cluster = glyphInfo[i].cluster - offset;
137
indices[storei] = baseIndex + cluster;
138
glyphs[storei] = (unsigned int)(glyphInfo[i].codepoint | slot);
139
positions[storei*2] = startX + x + glyphPos[i].x_offset * scale;
140
positions[(storei*2)+1] = startY + y - glyphPos[i].y_offset * scale;
141
x += glyphPos[i].x_advance * scale;
142
y += glyphPos[i].y_advance * scale;
143
storei++;
144
}
145
storeadv = initialCount + glyphCount;
146
// The final slot in the positions array is important
147
// because when the GlyphVector is created from this
148
// data it determines the overall advance of the glyphvector
149
// and this is used in positioning the next glyphvector
150
// during rendering where text is broken into runs.
151
// We also need to report it back into "pt", so layout can
152
// pass it back down for that next run in this code.
153
advX = startX + x;
154
advY = startY + y;
155
positions[(storeadv*2)] = advX;
156
positions[(storeadv*2)+1] = advY;
157
(*env)->ReleasePrimitiveArrayCritical(env, glyphArray, glyphs, 0);
158
(*env)->ReleasePrimitiveArrayCritical(env, posArray, positions, 0);
159
(*env)->ReleasePrimitiveArrayCritical(env, inxArray, indices, 0);
160
putFloat(env, startPt, advX, advY);
161
(*env)->SetIntField(env, gvdata, gvdCountFID, storeadv);
162
163
return JNI_TRUE;
164
}
165
166
static float euclidianDistance(float a, float b)
167
{
168
float root;
169
if (a < 0) {
170
a = -a;
171
}
172
173
if (b < 0) {
174
b = -b;
175
}
176
177
if (a == 0) {
178
return b;
179
}
180
181
if (b == 0) {
182
return a;
183
}
184
185
/* Do an initial approximation, in root */
186
root = a > b ? a + (b / 2) : b + (a / 2);
187
188
/* An unrolled Newton-Raphson iteration sequence */
189
root = (root + (a * (a / root)) + (b * (b / root)) + 1) / 2;
190
root = (root + (a * (a / root)) + (b * (b / root)) + 1) / 2;
191
root = (root + (a * (a / root)) + (b * (b / root)) + 1) / 2;
192
193
return root;
194
}
195
196
JDKFontInfo*
197
createJDKFontInfo(JNIEnv *env,
198
jobject font2D,
199
jobject fontStrike,
200
jfloat ptSize,
201
jfloatArray matrix) {
202
203
204
JDKFontInfo *fi = (JDKFontInfo*)malloc(sizeof(JDKFontInfo));
205
if (!fi) {
206
return NULL;
207
}
208
fi->env = env; // this is valid only for the life of this JNI call.
209
fi->font2D = font2D;
210
fi->fontStrike = fontStrike;
211
(*env)->GetFloatArrayRegion(env, matrix, 0, 4, fi->matrix);
212
fi->ptSize = ptSize;
213
fi->xPtSize = euclidianDistance(fi->matrix[0], fi->matrix[1]);
214
fi->yPtSize = euclidianDistance(fi->matrix[2], fi->matrix[3]);
215
if (getenv("HB_NODEVTX") != NULL) {
216
fi->devScale = fi->xPtSize / fi->ptSize;
217
} else {
218
fi->devScale = 1.0f;
219
}
220
return fi;
221
}
222
223
224
#define TYPO_KERN 0x00000001
225
#define TYPO_LIGA 0x00000002
226
#define TYPO_RTL 0x80000000
227
228
JNIEXPORT jboolean JNICALL Java_sun_font_SunLayoutEngine_shape
229
(JNIEnv *env, jclass cls,
230
jobject font2D,
231
jobject fontStrike,
232
jfloat ptSize,
233
jfloatArray matrix,
234
jlong pFace,
235
jcharArray text,
236
jobject gvdata,
237
jint script,
238
jint offset,
239
jint limit,
240
jint baseIndex,
241
jobject startPt,
242
jint flags,
243
jint slot) {
244
245
hb_buffer_t *buffer;
246
hb_face_t* hbface;
247
hb_font_t* hbfont;
248
jchar *chars;
249
jsize len;
250
int glyphCount;
251
hb_glyph_info_t *glyphInfo;
252
hb_glyph_position_t *glyphPos;
253
hb_direction_t direction = HB_DIRECTION_LTR;
254
hb_feature_t *features = NULL;
255
int featureCount = 0;
256
char* kern = (flags & TYPO_KERN) ? "kern" : "-kern";
257
char* liga = (flags & TYPO_LIGA) ? "liga" : "-liga";
258
jboolean ret;
259
unsigned int buflen;
260
261
JDKFontInfo *jdkFontInfo =
262
createJDKFontInfo(env, font2D, fontStrike, ptSize, matrix);
263
if (!jdkFontInfo) {
264
return JNI_FALSE;
265
}
266
jdkFontInfo->env = env; // this is valid only for the life of this JNI call.
267
jdkFontInfo->font2D = font2D;
268
jdkFontInfo->fontStrike = fontStrike;
269
270
hbface = (hb_face_t*) jlong_to_ptr(pFace);
271
hbfont = hb_jdk_font_create(hbface, jdkFontInfo, NULL);
272
273
buffer = hb_buffer_create();
274
hb_buffer_set_script(buffer, getHBScriptCode(script));
275
hb_buffer_set_language(buffer,
276
hb_ot_tag_to_language(HB_OT_TAG_DEFAULT_LANGUAGE));
277
if ((flags & TYPO_RTL) != 0) {
278
direction = HB_DIRECTION_RTL;
279
}
280
hb_buffer_set_direction(buffer, direction);
281
hb_buffer_set_cluster_level(buffer,
282
HB_BUFFER_CLUSTER_LEVEL_MONOTONE_CHARACTERS);
283
284
chars = (*env)->GetCharArrayElements(env, text, NULL);
285
if ((*env)->ExceptionCheck(env)) {
286
hb_buffer_destroy(buffer);
287
hb_font_destroy(hbfont);
288
free((void*)jdkFontInfo);
289
return JNI_FALSE;
290
}
291
len = (*env)->GetArrayLength(env, text);
292
293
hb_buffer_add_utf16(buffer, chars, len, offset, limit-offset);
294
295
features = calloc(2, sizeof(hb_feature_t));
296
if (features) {
297
hb_feature_from_string(kern, -1, &features[featureCount++]);
298
hb_feature_from_string(liga, -1, &features[featureCount++]);
299
}
300
301
hb_shape_full(hbfont, buffer, features, featureCount, 0);
302
glyphCount = hb_buffer_get_length(buffer);
303
glyphInfo = hb_buffer_get_glyph_infos(buffer, 0);
304
glyphPos = hb_buffer_get_glyph_positions(buffer, &buflen);
305
306
ret = storeGVData(env, gvdata, slot, baseIndex, offset, startPt,
307
limit - offset, glyphCount, glyphInfo, glyphPos,
308
jdkFontInfo->devScale);
309
310
hb_buffer_destroy (buffer);
311
hb_font_destroy(hbfont);
312
free((void*)jdkFontInfo);
313
if (features != NULL) free(features);
314
(*env)->ReleaseCharArrayElements(env, text, chars, JNI_ABORT);
315
return ret;
316
}
317
318
319