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 if (buffer == NULL) { 355 return NULL; 356 } 357 env->GetByteArrayRegion(tableBytes, 0, length, (jbyte*)buffer); 358 359 return hb_blob_create((const char *)buffer, length, 360 HB_MEMORY_MODE_WRITABLE, 361 buffer, free); 362 } 363 364 extern "C" { 365 366 /* 367 * Class: sun_font_SunLayoutEngine 368 * Method: createFace 369 * Signature: (Lsun/font/Font2D;ZJJ)J 370 */ 371 JNIEXPORT jlong JNICALL Java_sun_font_SunLayoutEngine_createFace(JNIEnv *env, 372 jclass cls, 373 jobject font2D, 374 jboolean aat, 375 jlong platformFontPtr) { 376 #ifdef MACOSX 377 if (aat && platformFontPtr) { 378 hb_face_t *face = hb_coretext_face_create((CGFontRef)platformFontPtr); 379 return ptr_to_jlong(face); 380 } 381 #endif 382 Font2DPtr *fi = (Font2DPtr*)malloc(sizeof(Font2DPtr)); 383 if (!fi) { 384 return 0; 385 } 386 JavaVM* vmPtr; 387 env->GetJavaVM(&vmPtr); 388 fi->vmPtr = vmPtr; 389 fi->font2DRef = env->NewWeakGlobalRef(font2D); 390 if (!fi->font2DRef) { 391 free(fi); 392 return 0; 393 } 394 hb_face_t *face = hb_face_create_for_tables(reference_table, fi, 395 cleanupFontInfo); 396 return ptr_to_jlong(face); 397 } 398 399 /* 400 * Class: sun_font_SunLayoutEngine 401 * Method: disposeFace 402 * Signature: (J)V 403 */ 404 JNIEXPORT void JNICALL Java_sun_font_SunLayoutEngine_disposeFace(JNIEnv *env, 405 jclass cls, 406 jlong ptr) { 407 hb_face_t* face = (hb_face_t*) jlong_to_ptr(ptr); 408 hb_face_destroy(face); 409 } 410 411 } // extern "C" 412 413 static hb_font_t* _hb_jdk_font_create(hb_face_t* face, 414 JDKFontInfo *jdkFontInfo, 415 hb_destroy_func_t destroy) { 416 417 hb_font_t *font; 418 419 font = hb_font_create(face); 420 hb_font_set_funcs (font, 421 _hb_jdk_get_font_funcs (), 422 jdkFontInfo, (hb_destroy_func_t) _do_nothing); 423 hb_font_set_scale (font, 424 HBFloatToFixed(jdkFontInfo->ptSize*jdkFontInfo->devScale), 425 HBFloatToFixed(jdkFontInfo->ptSize*jdkFontInfo->devScale)); 426 return font; 427 } 428 429 #ifdef MACOSX 430 static hb_font_t* _hb_jdk_ct_font_create(hb_face_t* face, 431 JDKFontInfo *jdkFontInfo) { 432 433 hb_font_t *font = NULL; 434 font = hb_font_create(face); 435 hb_font_set_scale(font, 436 HBFloatToFixed(jdkFontInfo->ptSize), 437 HBFloatToFixed(jdkFontInfo->ptSize)); 438 return font; 439 } 440 #endif 441 442 hb_font_t* hb_jdk_font_create(hb_face_t* hbFace, 443 JDKFontInfo *jdkFontInfo, 444 hb_destroy_func_t destroy) { 445 #ifdef MACOSX 446 if (jdkFontInfo->aat && jdkFontInfo->nativeFont) { 447 return _hb_jdk_ct_font_create(hbFace, jdkFontInfo); 448 } 449 #endif 450 return _hb_jdk_font_create(hbFace, jdkFontInfo, destroy); 451 }