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