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 }