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 "jlong.h" |
27 | #include "sun_font_SunLayoutEngine.h" |
28 | |
29 | #include "hb.h" |
30 | #include "hb-jdk.h" |
31 | #ifdef MACOSX |
32 | #include "hb-coretext.h" |
33 | #endif |
34 | #include <stdlib.h> |
35 | |
36 | #if defined(__GNUC__) && __GNUC__ >= 4 |
37 | #define HB_UNUSED __attribute__((unused)) |
38 | #else |
39 | #define HB_UNUSED |
40 | #endif |
41 | |
42 | |
43 | static hb_bool_t |
44 | hb_jdk_get_nominal_glyph (hb_font_t *font HB_UNUSED, |
45 | void *font_data, |
46 | hb_codepoint_t unicode, |
47 | hb_codepoint_t *glyph, |
48 | void *user_data HB_UNUSED) |
49 | { |
50 | |
51 | JDKFontInfo *jdkFontInfo = (JDKFontInfo*)font_data; |
52 | JNIEnv* env = jdkFontInfo->env; |
53 | jobject font2D = jdkFontInfo->font2D; |
54 | *glyph = (hb_codepoint_t)env->CallIntMethod( |
55 | font2D, sunFontIDs.f2dCharToGlyphMID, unicode); |
56 | if (env->ExceptionOccurred()) |
57 | { |
58 | env->ExceptionClear(); |
59 | } |
60 | if ((int)*glyph < 0) { |
61 | *glyph = 0; |
62 | } |
63 | return (*glyph != 0); |
64 | } |
65 | |
66 | static hb_bool_t |
67 | hb_jdk_get_variation_glyph (hb_font_t *font HB_UNUSED, |
68 | void *font_data, |
69 | hb_codepoint_t unicode, |
70 | hb_codepoint_t variation_selector, |
71 | hb_codepoint_t *glyph, |
72 | void *user_data HB_UNUSED) |
73 | { |
74 | |
75 | JDKFontInfo *jdkFontInfo = (JDKFontInfo*)font_data; |
76 | JNIEnv* env = jdkFontInfo->env; |
77 | jobject font2D = jdkFontInfo->font2D; |
78 | *glyph = (hb_codepoint_t)env->CallIntMethod( |
79 | font2D, sunFontIDs.f2dCharToVariationGlyphMID, |
80 | unicode, variation_selector); |
81 | if (env->ExceptionOccurred()) |
82 | { |
83 | env->ExceptionClear(); |
84 | } |
85 | if ((int)*glyph < 0) { |
86 | *glyph = 0; |
87 | } |
88 | return (*glyph != 0); |
89 | } |
90 | |
91 | static hb_position_t |
92 | hb_jdk_get_glyph_h_advance (hb_font_t *font HB_UNUSED, |
93 | void *font_data, |
94 | hb_codepoint_t glyph, |
95 | void *user_data HB_UNUSED) |
96 | { |
97 | |
98 | float fadv = 0.0f; |
99 | if ((glyph & 0xfffe) == 0xfffe) { |
100 | return 0; // JDK uses this glyph code. |
101 | } |
102 | |
103 | JDKFontInfo *jdkFontInfo = (JDKFontInfo*)font_data; |
104 | JNIEnv* env = jdkFontInfo->env; |
105 | jobject fontStrike = jdkFontInfo->fontStrike; |
106 | jobject pt = env->CallObjectMethod(fontStrike, |
107 | sunFontIDs.getGlyphMetricsMID, glyph); |
108 | |
109 | if (pt == NULL) { |
110 | return 0; |
111 | } |
112 | fadv = env->GetFloatField(pt, sunFontIDs.xFID); |
113 | fadv *= jdkFontInfo->devScale; |
114 | env->DeleteLocalRef(pt); |
115 | |
116 | return HBFloatToFixed(fadv); |
117 | } |
118 | |
119 | static hb_position_t |
120 | hb_jdk_get_glyph_v_advance (hb_font_t *font HB_UNUSED, |
121 | void *font_data, |
122 | hb_codepoint_t glyph, |
123 | void *user_data HB_UNUSED) |
124 | { |
125 | |
126 | float fadv = 0.0f; |
127 | if ((glyph & 0xfffe) == 0xfffe) { |
128 | return 0; // JDK uses this glyph code. |
129 | } |
130 | |
131 | JDKFontInfo *jdkFontInfo = (JDKFontInfo*)font_data; |
132 | JNIEnv* env = jdkFontInfo->env; |
133 | jobject fontStrike = jdkFontInfo->fontStrike; |
134 | jobject pt = env->CallObjectMethod(fontStrike, |
135 | sunFontIDs.getGlyphMetricsMID, glyph); |
136 | |
137 | if (pt == NULL) { |
138 | return 0; |
139 | } |
140 | fadv = env->GetFloatField(pt, sunFontIDs.yFID); |
141 | env->DeleteLocalRef(pt); |
142 | |
143 | return HBFloatToFixed(fadv); |
144 | |
145 | } |
146 | |
147 | static hb_bool_t |
148 | hb_jdk_get_glyph_h_origin (hb_font_t *font HB_UNUSED, |
149 | void *font_data HB_UNUSED, |
150 | hb_codepoint_t glyph HB_UNUSED, |
151 | hb_position_t *x HB_UNUSED, |
152 | hb_position_t *y HB_UNUSED, |
153 | void *user_data HB_UNUSED) |
154 | { |
155 | /* We always work in the horizontal coordinates. */ |
156 | return true; |
157 | } |
158 | |
159 | static hb_bool_t |
160 | hb_jdk_get_glyph_v_origin (hb_font_t *font HB_UNUSED, |
161 | void *font_data, |
162 | hb_codepoint_t glyph, |
163 | hb_position_t *x, |
164 | hb_position_t *y, |
165 | void *user_data HB_UNUSED) |
166 | { |
167 | return false; |
168 | } |
169 | |
170 | static hb_position_t |
171 | hb_jdk_get_glyph_h_kerning (hb_font_t *font, |
172 | void *font_data, |
173 | hb_codepoint_t lejdk_glyph, |
174 | hb_codepoint_t right_glyph, |
175 | void *user_data HB_UNUSED) |
176 | { |
177 | /* Not implemented. This seems to be in the HB API |
178 | * as a way to fall back to Freetype's kerning support |
179 | * which could be based on some on-the fly glyph analysis. |
180 | * But more likely it reads the kern table. That is easy |
181 | * enough code to add if we find a need to fall back |
182 | * to that instead of using gpos. It seems like if |
183 | * there is a gpos table at all, the practice is to |
184 | * use that and ignore kern, no matter that gpos does |
185 | * not implement the kern feature. |
186 | */ |
187 | return 0; |
188 | } |
189 | |
190 | static hb_position_t |
191 | hb_jdk_get_glyph_v_kerning (hb_font_t *font HB_UNUSED, |
192 | void *font_data HB_UNUSED, |
193 | hb_codepoint_t top_glyph HB_UNUSED, |
194 | hb_codepoint_t bottom_glyph HB_UNUSED, |
195 | void *user_data HB_UNUSED) |
196 | { |
197 | /* OpenType doesn't have vertical-kerning other than GPOS. */ |
198 | return 0; |
199 | } |
200 | |
201 | static hb_bool_t |
202 | hb_jdk_get_glyph_extents (hb_font_t *font HB_UNUSED, |
203 | void *font_data, |
204 | hb_codepoint_t glyph, |
205 | hb_glyph_extents_t *extents, |
206 | void *user_data HB_UNUSED) |
207 | { |
208 | /* TODO */ |
209 | return false; |
210 | } |
211 | |
212 | static hb_bool_t |
213 | hb_jdk_get_glyph_contour_point (hb_font_t *font HB_UNUSED, |
214 | void *font_data, |
215 | hb_codepoint_t glyph, |
216 | unsigned int point_index, |
217 | hb_position_t *x, |
218 | hb_position_t *y, |
219 | void *user_data HB_UNUSED) |
220 | { |
221 | if ((glyph & 0xfffe) == 0xfffe) { |
222 | *x = 0; *y = 0; |
223 | return true; |
224 | } |
225 | |
226 | JDKFontInfo *jdkFontInfo = (JDKFontInfo*)font_data; |
227 | JNIEnv* env = jdkFontInfo->env; |
228 | jobject fontStrike = jdkFontInfo->fontStrike; |
229 | jobject pt = env->CallObjectMethod(fontStrike, |
230 | sunFontIDs.getGlyphPointMID, |
231 | glyph, point_index); |
232 | |
233 | if (pt == NULL) { |
234 | *x = 0; *y = 0; |
235 | return true; |
236 | } |
237 | *x = HBFloatToFixed(env->GetFloatField(pt, sunFontIDs.xFID)); |
238 | *y = HBFloatToFixed(env->GetFloatField(pt, sunFontIDs.yFID)); |
239 | env->DeleteLocalRef(pt); |
240 | |
241 | return true; |
242 | } |
243 | |
244 | static hb_bool_t |
245 | hb_jdk_get_glyph_name (hb_font_t *font HB_UNUSED, |
246 | void *font_data, |
247 | hb_codepoint_t glyph, |
248 | char *name, unsigned int size, |
249 | void *user_data HB_UNUSED) |
250 | { |
251 | return false; |
252 | } |
253 | |
254 | static hb_bool_t |
255 | hb_jdk_get_glyph_from_name (hb_font_t *font HB_UNUSED, |
256 | void *font_data, |
257 | const char *name, int len, |
258 | hb_codepoint_t *glyph, |
259 | void *user_data HB_UNUSED) |
260 | { |
261 | return false; |
262 | } |
263 | |
264 | // remind : can we initialise this from the code we call |
265 | // from the class static method in Java to make it |
266 | // completely thread safe. |
267 | static hb_font_funcs_t * |
268 | _hb_jdk_get_font_funcs (void) |
269 | { |
270 | static hb_font_funcs_t *jdk_ffuncs = NULL; |
271 | hb_font_funcs_t *ff; |
272 | |
273 | if (!jdk_ffuncs) { |
274 | ff = hb_font_funcs_create(); |
275 | |
276 | hb_font_funcs_set_nominal_glyph_func(ff, hb_jdk_get_nominal_glyph, NULL, NULL); |
277 | hb_font_funcs_set_variation_glyph_func(ff, hb_jdk_get_variation_glyph, NULL, NULL); |
278 | hb_font_funcs_set_glyph_h_advance_func(ff, |
279 | hb_jdk_get_glyph_h_advance, NULL, NULL); |
280 | hb_font_funcs_set_glyph_v_advance_func(ff, |
281 | hb_jdk_get_glyph_v_advance, NULL, NULL); |
282 | hb_font_funcs_set_glyph_h_origin_func(ff, |
283 | hb_jdk_get_glyph_h_origin, NULL, NULL); |
284 | hb_font_funcs_set_glyph_v_origin_func(ff, |
285 | hb_jdk_get_glyph_v_origin, NULL, NULL); |
286 | hb_font_funcs_set_glyph_h_kerning_func(ff, |
287 | hb_jdk_get_glyph_h_kerning, NULL, NULL); |
288 | hb_font_funcs_set_glyph_v_kerning_func(ff, |
289 | hb_jdk_get_glyph_v_kerning, NULL, NULL); |
290 | hb_font_funcs_set_glyph_extents_func(ff, |
291 | hb_jdk_get_glyph_extents, NULL, NULL); |
292 | hb_font_funcs_set_glyph_contour_point_func(ff, |
293 | hb_jdk_get_glyph_contour_point, NULL, NULL); |
294 | hb_font_funcs_set_glyph_name_func(ff, |
295 | hb_jdk_get_glyph_name, NULL, NULL); |
296 | hb_font_funcs_set_glyph_from_name_func(ff, |
297 | hb_jdk_get_glyph_from_name, NULL, NULL); |
298 | hb_font_funcs_make_immutable(ff); // done setting functions. |
299 | jdk_ffuncs = ff; |
300 | } |
301 | return jdk_ffuncs; |
302 | } |
303 | |
304 | static void _do_nothing(void) { |
305 | } |
306 | |
307 | static void _free_nothing(void*) { |
308 | } |
309 | |
310 | struct Font2DPtr { |
311 | JavaVM* vmPtr; |
312 | jweak font2DRef; |
313 | }; |
314 | |
315 | static void cleanupFontInfo(void* data) { |
316 | Font2DPtr* fontInfo; |
317 | JNIEnv* env; |
318 | |
319 | fontInfo = (Font2DPtr*) data; |
320 | fontInfo->vmPtr->GetEnv((void**)&env, JNI_VERSION_1_1); |
321 | env->DeleteWeakGlobalRef(fontInfo->font2DRef); |
322 | free(data); |
323 | } |
324 | |
325 | static hb_blob_t * |
326 | reference_table(hb_face_t *face HB_UNUSED, hb_tag_t tag, void *user_data) { |
327 | |
328 | Font2DPtr *fontInfo; |
329 | JNIEnv* env; |
330 | jobject font2D; |
331 | jsize length; |
332 | void* buffer; |
333 | |
334 | // HB_TAG_NONE is 0 and is used to get the whole font file. |
335 | // It is not expected to be needed for JDK. |
336 | if (tag == 0) { |
337 | return NULL; |
338 | } |
339 | |
340 | fontInfo = (Font2DPtr*)user_data; |
341 | fontInfo->vmPtr->GetEnv((void**)&env, JNI_VERSION_1_1); |
342 | if (env == NULL) { |
343 | return NULL; |
344 | } |
345 | font2D = fontInfo->font2DRef; |
346 | |
347 | jbyteArray tableBytes = (jbyteArray) |
348 | env->CallObjectMethod(font2D, sunFontIDs.getTableBytesMID, tag); |
349 | if (tableBytes == NULL) { |
350 | return NULL; |
351 | } |
352 | length = env->GetArrayLength(tableBytes); |
353 | buffer = calloc(length, sizeof(jbyte)); |
354 | env->GetByteArrayRegion(tableBytes, 0, length, (jbyte*)buffer); |
355 | |
356 | return hb_blob_create((const char *)buffer, length, |
357 | HB_MEMORY_MODE_WRITABLE, |
358 | buffer, free); |
359 | } |
360 | |
361 | extern "C" { |
362 | |
363 | /* |
364 | * Class: sun_font_SunLayoutEngine |
365 | * Method: createFace |
366 | * Signature: (Lsun/font/Font2D;ZJJ)J |
367 | */ |
368 | JNIEXPORT jlong JNICALL Java_sun_font_SunLayoutEngine_createFace(JNIEnv *env, |
369 | jclass cls, |
370 | jobject font2D, |
371 | jboolean aat, |
372 | jlong platformFontPtr) { |
373 | #ifdef MACOSX |
374 | if (aat && platformFontPtr) { |
375 | hb_face_t *face = hb_coretext_face_create((CGFontRef)platformFontPtr); |
376 | return ptr_to_jlong(face); |
377 | } |
378 | #endif |
379 | Font2DPtr *fi = (Font2DPtr*)malloc(sizeof(Font2DPtr)); |
380 | if (!fi) { |
381 | return 0; |
382 | } |
383 | JavaVM* vmPtr; |
384 | env->GetJavaVM(&vmPtr); |
385 | fi->vmPtr = vmPtr; |
386 | fi->font2DRef = env->NewWeakGlobalRef(font2D); |
387 | if (!fi->font2DRef) { |
388 | free(fi); |
389 | return 0; |
390 | } |
391 | hb_face_t *face = hb_face_create_for_tables(reference_table, fi, |
392 | cleanupFontInfo); |
393 | return ptr_to_jlong(face); |
394 | } |
395 | |
396 | /* |
397 | * Class: sun_font_SunLayoutEngine |
398 | * Method: disposeFace |
399 | * Signature: (J)V |
400 | */ |
401 | JNIEXPORT void JNICALL Java_sun_font_SunLayoutEngine_disposeFace(JNIEnv *env, |
402 | jclass cls, |
403 | jlong ptr) { |
404 | hb_face_t* face = (hb_face_t*) jlong_to_ptr(ptr); |
405 | hb_face_destroy(face); |
406 | } |
407 | |
408 | } // extern "C" |
409 | |
410 | static hb_font_t* _hb_jdk_font_create(hb_face_t* face, |
411 | JDKFontInfo *jdkFontInfo, |
412 | hb_destroy_func_t destroy) { |
413 | |
414 | hb_font_t *font; |
415 | |
416 | font = hb_font_create(face); |
417 | hb_font_set_funcs (font, |
418 | _hb_jdk_get_font_funcs (), |
419 | jdkFontInfo, (hb_destroy_func_t) _do_nothing); |
420 | hb_font_set_scale (font, |
421 | HBFloatToFixed(jdkFontInfo->ptSize*jdkFontInfo->devScale), |
422 | HBFloatToFixed(jdkFontInfo->ptSize*jdkFontInfo->devScale)); |
423 | return font; |
424 | } |
425 | |
426 | #ifdef MACOSX |
427 | static hb_font_t* _hb_jdk_ct_font_create(hb_face_t* face, |
428 | JDKFontInfo *jdkFontInfo) { |
429 | |
430 | hb_font_t *font = NULL; |
431 | font = hb_font_create(face); |
432 | hb_font_set_scale(font, |
433 | HBFloatToFixed(jdkFontInfo->ptSize), |
434 | HBFloatToFixed(jdkFontInfo->ptSize)); |
435 | return font; |
436 | } |
437 | #endif |
438 | |
439 | hb_font_t* hb_jdk_font_create(hb_face_t* hbFace, |
440 | JDKFontInfo *jdkFontInfo, |
441 | hb_destroy_func_t destroy) { |
442 | #ifdef MACOSX |
443 | if (jdkFontInfo->aat && jdkFontInfo->nativeFont) { |
444 | return _hb_jdk_ct_font_create(hbFace, jdkFontInfo); |
445 | } |
446 | #endif |
447 | return _hb_jdk_font_create(hbFace, jdkFontInfo, destroy); |
448 | } |
449 | |