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