1 /*
   2  * Copyright (c) 2007, 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 "stdlib.h"
  27 #include "string.h"
  28 #include "gdefs.h"
  29 #include "jlong.h"
  30 #include "jni_util.h"
  31 #include "sunfontids.h"
  32 #include "fontscalerdefs.h"
  33 #include "sun_font_SunFontManager.h"
  34 #include "sun_font_NullFontScaler.h"
  35 #include "sun_font_StrikeCache.h"
  36 
  37 static void *theNullScalerContext = NULL;
  38 extern void AccelGlyphCache_RemoveAllCellInfos(GlyphInfo *glyph);
  39 
  40 /*
  41  * Declare library specific JNI_Onload entry if static build
  42  */
  43 DEF_STATIC_JNI_OnLoad
  44 
  45 JNIEXPORT jlong JNICALL
  46 Java_sun_font_NullFontScaler_getNullScalerContext
  47     (JNIEnv *env, jclass scalerClass) {
  48 
  49     if (theNullScalerContext == NULL) {
  50         theNullScalerContext = malloc(1);
  51     }
  52     return ptr_to_jlong(theNullScalerContext);
  53 }
  54 
  55 int isNullScalerContext(void *context) {
  56     return theNullScalerContext == context;
  57 }
  58 
  59 /* Eventually we may rework it to be a singleton.
  60  * This will require additional checks in freeLongMemory/freeIntMemory
  61  * and on other hand malformed fonts (main source of null glyph images)
  62  * are supposed to be collected fast.
  63  * But perhaps it is still right thing to do.
  64  * Even better is to eliminate the need to have this native method
  65  * but for this it is necessary to rework Strike and drawing logic
  66  * to be able to live with NULL pointers without performance hit.
  67  */
  68 JNIEXPORT jlong JNICALL Java_sun_font_NullFontScaler_getGlyphImage
  69   (JNIEnv *env, jobject scaler, jlong pContext, jint glyphCode) {
  70     void *nullscaler = calloc(sizeof(GlyphInfo), 1);
  71     return ptr_to_jlong(nullscaler);
  72 }
  73 
  74 
  75 
  76 void initLCDGammaTables();
  77 
  78 /* placeholder for extern variable */
  79 static int initialisedFontIDs = 0;
  80 FontManagerNativeIDs sunFontIDs;
  81 
  82 static void initFontIDs(JNIEnv *env) {
  83 
  84      jclass tmpClass;
  85 
  86      if (initialisedFontIDs) {
  87         return;
  88      }
  89      CHECK_NULL(tmpClass = (*env)->FindClass(env, "sun/font/TrueTypeFont"));
  90      CHECK_NULL(sunFontIDs.ttReadBlockMID =
  91          (*env)->GetMethodID(env, tmpClass, "readBlock",
  92                              "(Ljava/nio/ByteBuffer;II)I"));
  93      CHECK_NULL(sunFontIDs.ttReadBytesMID =
  94          (*env)->GetMethodID(env, tmpClass, "readBytes", "(II)[B"));
  95 
  96      CHECK_NULL(tmpClass = (*env)->FindClass(env, "sun/font/Type1Font"));
  97      CHECK_NULL(sunFontIDs.readFileMID =
  98          (*env)->GetMethodID(env, tmpClass,
  99                              "readFile", "(Ljava/nio/ByteBuffer;)V"));
 100 
 101      CHECK_NULL(tmpClass =
 102          (*env)->FindClass(env, "java/awt/geom/Point2D$Float"));
 103      sunFontIDs.pt2DFloatClass = (jclass)(*env)->NewGlobalRef(env, tmpClass);
 104      CHECK_NULL(sunFontIDs.pt2DFloatCtr =
 105          (*env)->GetMethodID(env, sunFontIDs.pt2DFloatClass, "<init>","(FF)V"));
 106 
 107      CHECK_NULL(sunFontIDs.xFID =
 108          (*env)->GetFieldID(env, sunFontIDs.pt2DFloatClass, "x", "F"));
 109      CHECK_NULL(sunFontIDs.yFID =
 110          (*env)->GetFieldID(env, sunFontIDs.pt2DFloatClass, "y", "F"));
 111 
 112      CHECK_NULL(tmpClass = (*env)->FindClass(env, "sun/font/StrikeMetrics"));
 113      CHECK_NULL(sunFontIDs.strikeMetricsClass =
 114          (jclass)(*env)->NewGlobalRef(env, tmpClass));
 115 
 116      CHECK_NULL(sunFontIDs.strikeMetricsCtr =
 117          (*env)->GetMethodID(env, sunFontIDs.strikeMetricsClass,
 118                              "<init>", "(FFFFFFFFFF)V"));
 119 
 120      CHECK_NULL(tmpClass =
 121          (*env)->FindClass(env, "java/awt/geom/Rectangle2D$Float"));
 122      sunFontIDs.rect2DFloatClass = (jclass)(*env)->NewGlobalRef(env, tmpClass);
 123      CHECK_NULL(sunFontIDs.rect2DFloatCtr =
 124          (*env)->GetMethodID(env, sunFontIDs.rect2DFloatClass, "<init>", "()V"));
 125      CHECK_NULL(sunFontIDs.rect2DFloatCtr4 =
 126          (*env)->GetMethodID(env, sunFontIDs.rect2DFloatClass,
 127                             "<init>", "(FFFF)V"));
 128      CHECK_NULL(sunFontIDs.rectF2DX =
 129          (*env)->GetFieldID(env, sunFontIDs.rect2DFloatClass, "x", "F"));
 130      CHECK_NULL(sunFontIDs.rectF2DY =
 131          (*env)->GetFieldID(env, sunFontIDs.rect2DFloatClass, "y", "F"));
 132      CHECK_NULL(sunFontIDs.rectF2DWidth =
 133          (*env)->GetFieldID(env, sunFontIDs.rect2DFloatClass, "width", "F"));
 134      CHECK_NULL(sunFontIDs.rectF2DHeight =
 135          (*env)->GetFieldID(env, sunFontIDs.rect2DFloatClass, "height", "F"));
 136 
 137      CHECK_NULL(tmpClass = (*env)->FindClass(env, "java/awt/geom/GeneralPath"));
 138      sunFontIDs.gpClass = (jclass)(*env)->NewGlobalRef(env, tmpClass);
 139      CHECK_NULL(sunFontIDs.gpCtr =
 140          (*env)->GetMethodID(env, sunFontIDs.gpClass, "<init>", "(I[BI[FI)V"));
 141      CHECK_NULL(sunFontIDs.gpCtrEmpty =
 142          (*env)->GetMethodID(env, sunFontIDs.gpClass, "<init>", "()V"));
 143 
 144      CHECK_NULL(tmpClass = (*env)->FindClass(env, "sun/font/Font2D"));
 145      CHECK_NULL(sunFontIDs.f2dCharToGlyphMID =
 146          (*env)->GetMethodID(env, tmpClass, "charToGlyph", "(I)I"));
 147      CHECK_NULL(sunFontIDs.f2dCharsToGlyphsMID =
 148          (*env)->GetMethodID(env, tmpClass, "charsToGlyphs", "(I[I[I)V"));
 149      CHECK_NULL(sunFontIDs.getMapperMID =
 150          (*env)->GetMethodID(env, tmpClass, "getMapper",
 151                              "()Lsun/font/CharToGlyphMapper;"));
 152      CHECK_NULL(sunFontIDs.getTableBytesMID =
 153          (*env)->GetMethodID(env, tmpClass, "getTableBytes", "(I)[B"));
 154      CHECK_NULL(sunFontIDs.canDisplayMID =
 155          (*env)->GetMethodID(env, tmpClass, "canDisplay", "(C)Z"));
 156 
 157      CHECK_NULL(tmpClass = (*env)->FindClass(env, "sun/font/CharToGlyphMapper"));
 158      CHECK_NULL(sunFontIDs.charToGlyphMID =
 159         (*env)->GetMethodID(env, tmpClass, "charToGlyph", "(I)I"));
 160      CHECK_NULL(sunFontIDs.charsToGlyphsMID =
 161          (*env)->GetMethodID(env, tmpClass, "charsToGlyphs", "(I[I[I)V"));
 162 
 163      CHECK_NULL(tmpClass = (*env)->FindClass(env, "sun/font/PhysicalStrike"));
 164      CHECK_NULL(sunFontIDs.getGlyphMetricsMID =
 165          (*env)->GetMethodID(env, tmpClass, "getGlyphMetrics",
 166                              "(I)Ljava/awt/geom/Point2D$Float;"));
 167      CHECK_NULL(sunFontIDs.getGlyphPointMID =
 168          (*env)->GetMethodID(env, tmpClass, "getGlyphPoint",
 169                              "(II)Ljava/awt/geom/Point2D$Float;"));
 170      CHECK_NULL(sunFontIDs.adjustPointMID =
 171          (*env)->GetMethodID(env, tmpClass, "adjustPoint",
 172                              "(Ljava/awt/geom/Point2D$Float;)V"));
 173      CHECK_NULL(sunFontIDs.pScalerContextFID =
 174          (*env)->GetFieldID(env, tmpClass, "pScalerContext", "J"));
 175 
 176      CHECK_NULL(tmpClass = (*env)->FindClass(env, "sun/font/GlyphList"));
 177      CHECK_NULL(sunFontIDs.glyphListX =
 178          (*env)->GetFieldID(env, tmpClass, "x", "F"));
 179      CHECK_NULL(sunFontIDs.glyphListY =
 180          (*env)->GetFieldID(env, tmpClass, "y", "F"));
 181      CHECK_NULL(sunFontIDs.glyphListLen =
 182          (*env)->GetFieldID(env, tmpClass, "len", "I"));
 183      CHECK_NULL(sunFontIDs.glyphImages =
 184          (*env)->GetFieldID(env, tmpClass, "images", "[J"));
 185      CHECK_NULL(sunFontIDs.glyphListUsePos =
 186          (*env)->GetFieldID(env, tmpClass, "usePositions", "Z"));
 187      CHECK_NULL(sunFontIDs.glyphListPos =
 188          (*env)->GetFieldID(env, tmpClass, "positions", "[F"));
 189      CHECK_NULL(sunFontIDs.lcdRGBOrder =
 190          (*env)->GetFieldID(env, tmpClass, "lcdRGBOrder", "Z"));
 191      CHECK_NULL(sunFontIDs.lcdSubPixPos =
 192          (*env)->GetFieldID(env, tmpClass, "lcdSubPixPos", "Z"));
 193 
 194      initLCDGammaTables();
 195 
 196      initialisedFontIDs = 1;
 197 }
 198 
 199 JNIEXPORT void JNICALL
 200 Java_sun_font_SunFontManager_initIDs
 201     (JNIEnv *env, jclass cls) {
 202 
 203     initFontIDs(env);
 204 }
 205 
 206 JNIEXPORT FontManagerNativeIDs getSunFontIDs(JNIEnv *env) {
 207 
 208     initFontIDs(env);
 209     return sunFontIDs;
 210 }
 211 
 212 /*
 213  * Class:     sun_font_StrikeCache
 214  * Method:    freeIntPointer
 215  * Signature: (I)V
 216  */
 217 JNIEXPORT void JNICALL Java_sun_font_StrikeCache_freeIntPointer
 218     (JNIEnv *env, jclass cacheClass, jint ptr) {
 219 
 220     /* Note this is used for freeing a glyph which was allocated
 221      * but never placed into the glyph cache. The caller holds the
 222      * only reference, therefore it is unnecessary to invalidate any
 223      * accelerated glyph cache cells as we do in freeInt/LongMemory().
 224      */
 225     if (ptr != 0) {
 226         free((void*)((intptr_t)ptr));
 227     }
 228 }
 229 
 230 /*
 231  * Class:     sun_font_StrikeCache
 232  * Method:    freeLongPointer
 233  * Signature: (J)V
 234  */
 235 JNIEXPORT void JNICALL Java_sun_font_StrikeCache_freeLongPointer
 236     (JNIEnv *env, jclass cacheClass, jlong ptr) {
 237 
 238     /* Note this is used for freeing a glyph which was allocated
 239      * but never placed into the glyph cache. The caller holds the
 240      * only reference, therefore it is unnecessary to invalidate any
 241      * accelerated glyph cache cells as we do in freeInt/LongMemory().
 242      */
 243     if (ptr != 0L) {
 244         free(jlong_to_ptr(ptr));
 245     }
 246 }
 247 
 248 /*
 249  * Class:     sun_font_StrikeCache
 250  * Method:    freeIntMemory
 251  * Signature: ([I)V
 252  */
 253 JNIEXPORT void JNICALL Java_sun_font_StrikeCache_freeIntMemory
 254     (JNIEnv *env, jclass cacheClass, jintArray jmemArray, jlong pContext) {
 255 
 256     int len = (*env)->GetArrayLength(env, jmemArray);
 257     jint* ptrs =
 258         (jint*)(*env)->GetPrimitiveArrayCritical(env, jmemArray, NULL);
 259     int i;
 260 
 261     if (ptrs) {
 262         for (i=0; i< len; i++) {
 263             if (ptrs[i] != 0) {
 264                 GlyphInfo *ginfo = (GlyphInfo *)((intptr_t)ptrs[i]);
 265                 if (ginfo->cellInfo != NULL &&
 266                     ginfo->managed == MANAGED_GLYPH) {
 267                     // invalidate this glyph's accelerated cache cell
 268                     AccelGlyphCache_RemoveAllCellInfos(ginfo);
 269                 }
 270                 free(ginfo);
 271             }
 272         }
 273         (*env)->ReleasePrimitiveArrayCritical(env, jmemArray, ptrs, JNI_ABORT);
 274     }
 275     if (!isNullScalerContext(jlong_to_ptr(pContext))) {
 276         free(jlong_to_ptr(pContext));
 277     }
 278 }
 279 
 280 /*
 281  * Class:     sun_font_StrikeCache
 282  * Method:    freeLongMemory
 283  * Signature: ([J)V
 284  */
 285 JNIEXPORT void JNICALL Java_sun_font_StrikeCache_freeLongMemory
 286     (JNIEnv *env, jclass cacheClass, jlongArray jmemArray, jlong pContext) {
 287 
 288     int len = (*env)->GetArrayLength(env, jmemArray);
 289     jlong* ptrs =
 290         (jlong*)(*env)->GetPrimitiveArrayCritical(env, jmemArray, NULL);
 291     int i;
 292 
 293     if (ptrs) {
 294         for (i=0; i< len; i++) {
 295             if (ptrs[i] != 0L) {
 296                 GlyphInfo *ginfo = (GlyphInfo *) jlong_to_ptr(ptrs[i]);
 297                 if (ginfo->cellInfo != NULL &&
 298                     ginfo->managed == MANAGED_GLYPH) {
 299                     AccelGlyphCache_RemoveAllCellInfos(ginfo);
 300                 }
 301                 free((void*)ginfo);
 302             }
 303         }
 304         (*env)->ReleasePrimitiveArrayCritical(env, jmemArray, ptrs, JNI_ABORT);
 305     }
 306     if (!isNullScalerContext(jlong_to_ptr(pContext))) {
 307         free(jlong_to_ptr(pContext));
 308     }
 309 }
 310 
 311 JNIEXPORT void JNICALL
 312 Java_sun_font_StrikeCache_getGlyphCacheDescription
 313   (JNIEnv *env, jclass cls, jlongArray results) {
 314 
 315     jlong* nresults;
 316     GlyphInfo *info;
 317     size_t baseAddr;
 318 
 319     if ((*env)->GetArrayLength(env, results) < 13) {
 320         return;
 321     }
 322 
 323     nresults = (jlong*)(*env)->GetPrimitiveArrayCritical(env, results, NULL);
 324     if (nresults == NULL) {
 325         return;
 326     }
 327     info = (GlyphInfo*) calloc(1, sizeof(GlyphInfo));
 328     if (info == NULL) {
 329         (*env)->ReleasePrimitiveArrayCritical(env, results, nresults, 0);
 330         return;
 331     }
 332     baseAddr = (size_t)info;
 333     nresults[0] = sizeof(void*);
 334     nresults[1] = sizeof(GlyphInfo);
 335     nresults[2] = 0;
 336     nresults[3] = (size_t)&(info->advanceY)-baseAddr;
 337     nresults[4] = (size_t)&(info->width)-baseAddr;
 338     nresults[5] = (size_t)&(info->height)-baseAddr;
 339     nresults[6] = (size_t)&(info->rowBytes)-baseAddr;
 340     nresults[7] = (size_t)&(info->topLeftX)-baseAddr;
 341     nresults[8] = (size_t)&(info->topLeftY)-baseAddr;
 342     nresults[9] = (size_t)&(info->image)-baseAddr;
 343     nresults[10] = (jlong)(uintptr_t)info; /* invisible glyph */
 344     nresults[11] = (size_t)&(info->cellInfo)-baseAddr;
 345     nresults[12] = (size_t)&(info->managed)-baseAddr;
 346 
 347     (*env)->ReleasePrimitiveArrayCritical(env, results, nresults, 0);
 348 }
 349 
 350 JNIEXPORT TTLayoutTableCache* newLayoutTableCache() {
 351   TTLayoutTableCache* ltc = calloc(1, sizeof(TTLayoutTableCache));
 352   if (ltc) {
 353     int i;
 354     for(i=0;i<LAYOUTCACHE_ENTRIES;i++) {
 355       ltc->entries[i].len = -1;
 356     }
 357     ltc->entries[0].tag = GDEF_TAG;
 358     ltc->entries[1].tag = GPOS_TAG;
 359     ltc->entries[2].tag = GSUB_TAG;
 360     ltc->entries[3].tag = HEAD_TAG;
 361     ltc->entries[4].tag = KERN_TAG;
 362     ltc->entries[5].tag = MORT_TAG;
 363     ltc->entries[6].tag = MORX_TAG;
 364   }
 365   return ltc;
 366 }
 367 
 368 JNIEXPORT void freeLayoutTableCache(TTLayoutTableCache* ltc) {
 369   if (ltc) {
 370     int i;
 371     for(i=0;i<LAYOUTCACHE_ENTRIES;i++) {
 372       if(ltc->entries[i].ptr) free (ltc->entries[i].ptr);
 373     }
 374     if (ltc->kernPairs) free(ltc->kernPairs);
 375     free(ltc);
 376   }
 377 }