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