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