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