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