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