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