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
37static void *theNullScalerContext = NULL;
38extern void AccelGlyphCache_RemoveAllCellInfos(GlyphInfo *glyph);
39
40/*
41 * Declare library specific JNI_Onload entry if static build
42 */
43DEF_STATIC_JNI_OnLoad
44
45JNIEXPORT jlong JNICALL
46Java_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
55int 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 */
68JNIEXPORT 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
76void initLCDGammaTables();
77
78/* placeholder for extern variable */
79static int initialisedFontIDs = 0;
80FontManagerNativeIDs sunFontIDs;
81
82static 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.getMapperMID =
148         (*env)->GetMethodID(env, tmpClass, "getMapper",
149                             "()Lsun/font/CharToGlyphMapper;"));
150     CHECK_NULL(sunFontIDs.getTableBytesMID =
151         (*env)->GetMethodID(env, tmpClass, "getTableBytes", "(I)[B"));
152     CHECK_NULL(sunFontIDs.canDisplayMID =
153         (*env)->GetMethodID(env, tmpClass, "canDisplay", "(C)Z"));
154
155     CHECK_NULL(tmpClass = (*env)->FindClass(env, "sun/font/CharToGlyphMapper"));
156     CHECK_NULL(sunFontIDs.charToGlyphMID =
157        (*env)->GetMethodID(env, tmpClass, "charToGlyph", "(I)I"));
158
159     CHECK_NULL(tmpClass = (*env)->FindClass(env, "sun/font/PhysicalStrike"));
160     CHECK_NULL(sunFontIDs.getGlyphMetricsMID =
161         (*env)->GetMethodID(env, tmpClass, "getGlyphMetrics",
162                             "(I)Ljava/awt/geom/Point2D$Float;"));
163     CHECK_NULL(sunFontIDs.getGlyphPointMID =
164         (*env)->GetMethodID(env, tmpClass, "getGlyphPoint",
165                             "(II)Ljava/awt/geom/Point2D$Float;"));
166     CHECK_NULL(sunFontIDs.adjustPointMID =
167         (*env)->GetMethodID(env, tmpClass, "adjustPoint",
168                             "(Ljava/awt/geom/Point2D$Float;)V"));
169     CHECK_NULL(sunFontIDs.pScalerContextFID =
170         (*env)->GetFieldID(env, tmpClass, "pScalerContext", "J"));
171
172     CHECK_NULL(tmpClass = (*env)->FindClass(env, "sun/font/GlyphList"));
173     CHECK_NULL(sunFontIDs.glyphListX =
174         (*env)->GetFieldID(env, tmpClass, "x", "F"));
175     CHECK_NULL(sunFontIDs.glyphListY =
176         (*env)->GetFieldID(env, tmpClass, "y", "F"));
177     CHECK_NULL(sunFontIDs.glyphListLen =
178         (*env)->GetFieldID(env, tmpClass, "len", "I"));
179     CHECK_NULL(sunFontIDs.glyphImages =
180         (*env)->GetFieldID(env, tmpClass, "images", "[J"));
181     CHECK_NULL(sunFontIDs.glyphListUsePos =
182         (*env)->GetFieldID(env, tmpClass, "usePositions", "Z"));
183     CHECK_NULL(sunFontIDs.glyphListPos =
184         (*env)->GetFieldID(env, tmpClass, "positions", "[F"));
185     CHECK_NULL(sunFontIDs.lcdRGBOrder =
186         (*env)->GetFieldID(env, tmpClass, "lcdRGBOrder", "Z"));
187     CHECK_NULL(sunFontIDs.lcdSubPixPos =
188         (*env)->GetFieldID(env, tmpClass, "lcdSubPixPos", "Z"));
189
190     initLCDGammaTables();
191
192     initialisedFontIDs = 1;
193}
194
195JNIEXPORT void JNICALL
196Java_sun_font_SunFontManager_initIDs
197    (JNIEnv *env, jclass cls) {
198
199    initFontIDs(env);
200}
201
202JNIEXPORT FontManagerNativeIDs getSunFontIDs(JNIEnv *env) {
203
204    initFontIDs(env);
205    return sunFontIDs;
206}
207
208/*
209 * Class:     sun_font_StrikeCache
210 * Method:    freeIntPointer
211 * Signature: (I)V
212 */
213JNIEXPORT void JNICALL Java_sun_font_StrikeCache_freeIntPointer
214    (JNIEnv *env, jclass cacheClass, jint ptr) {
215
216    /* Note this is used for freeing a glyph which was allocated
217     * but never placed into the glyph cache. The caller holds the
218     * only reference, therefore it is unnecessary to invalidate any
219     * accelerated glyph cache cells as we do in freeInt/LongMemory().
220     */
221    if (ptr != 0) {
222        free((void*)ptr);
223    }
224}
225
226/*
227 * Class:     sun_font_StrikeCache
228 * Method:    freeLongPointer
229 * Signature: (J)V
230 */
231JNIEXPORT void JNICALL Java_sun_font_StrikeCache_freeLongPointer
232    (JNIEnv *env, jclass cacheClass, jlong ptr) {
233
234    /* Note this is used for freeing a glyph which was allocated
235     * but never placed into the glyph cache. The caller holds the
236     * only reference, therefore it is unnecessary to invalidate any
237     * accelerated glyph cache cells as we do in freeInt/LongMemory().
238     */
239    if (ptr != 0L) {
240        free(jlong_to_ptr(ptr));
241    }
242}
243
244/*
245 * Class:     sun_font_StrikeCache
246 * Method:    freeIntMemory
247 * Signature: ([I)V
248 */
249JNIEXPORT void JNICALL Java_sun_font_StrikeCache_freeIntMemory
250    (JNIEnv *env, jclass cacheClass, jintArray jmemArray, jlong pContext) {
251
252    int len = (*env)->GetArrayLength(env, jmemArray);
253    jint* ptrs =
254        (jint*)(*env)->GetPrimitiveArrayCritical(env, jmemArray, NULL);
255    int i;
256
257    if (ptrs) {
258        for (i=0; i< len; i++) {
259            if (ptrs[i] != 0) {
260                GlyphInfo *ginfo = (GlyphInfo *)ptrs[i];
261                if (ginfo->cellInfo != NULL &&
262                    ginfo->managed == MANAGED_GLYPH) {
263                    // invalidate this glyph's accelerated cache cell
264                    AccelGlyphCache_RemoveAllCellInfos(ginfo);
265                }
266                free((void*)ginfo);
267            }
268        }
269        (*env)->ReleasePrimitiveArrayCritical(env, jmemArray, ptrs, JNI_ABORT);
270    }
271    if (!isNullScalerContext(jlong_to_ptr(pContext))) {
272        free(jlong_to_ptr(pContext));
273    }
274}
275
276/*
277 * Class:     sun_font_StrikeCache
278 * Method:    freeLongMemory
279 * Signature: ([J)V
280 */
281JNIEXPORT void JNICALL Java_sun_font_StrikeCache_freeLongMemory
282    (JNIEnv *env, jclass cacheClass, jlongArray jmemArray, jlong pContext) {
283
284    int len = (*env)->GetArrayLength(env, jmemArray);
285    jlong* ptrs =
286        (jlong*)(*env)->GetPrimitiveArrayCritical(env, jmemArray, NULL);
287    int i;
288
289    if (ptrs) {
290        for (i=0; i< len; i++) {
291            if (ptrs[i] != 0L) {
292                GlyphInfo *ginfo = (GlyphInfo *) jlong_to_ptr(ptrs[i]);
293                if (ginfo->cellInfo != NULL &&
294                    ginfo->managed == MANAGED_GLYPH) {
295                    AccelGlyphCache_RemoveAllCellInfos(ginfo);
296                }
297                free((void*)ginfo);
298            }
299        }
300        (*env)->ReleasePrimitiveArrayCritical(env, jmemArray, ptrs, JNI_ABORT);
301    }
302    if (!isNullScalerContext(jlong_to_ptr(pContext))) {
303        free(jlong_to_ptr(pContext));
304    }
305}
306
307JNIEXPORT void JNICALL
308Java_sun_font_StrikeCache_getGlyphCacheDescription
309  (JNIEnv *env, jclass cls, jlongArray results) {
310
311    jlong* nresults;
312    GlyphInfo *info;
313    size_t baseAddr;
314
315    if ((*env)->GetArrayLength(env, results) < 13) {
316        return;
317    }
318
319    nresults = (jlong*)(*env)->GetPrimitiveArrayCritical(env, results, NULL);
320    if (nresults == NULL) {
321        return;
322    }
323    info = (GlyphInfo*) calloc(1, sizeof(GlyphInfo));
324    if (info == NULL) {
325        (*env)->ReleasePrimitiveArrayCritical(env, results, nresults, 0);
326        return;
327    }
328    baseAddr = (size_t)info;
329    nresults[0] = sizeof(void*);
330    nresults[1] = sizeof(GlyphInfo);
331    nresults[2] = 0;
332    nresults[3] = (size_t)&(info->advanceY)-baseAddr;
333    nresults[4] = (size_t)&(info->width)-baseAddr;
334    nresults[5] = (size_t)&(info->height)-baseAddr;
335    nresults[6] = (size_t)&(info->rowBytes)-baseAddr;
336    nresults[7] = (size_t)&(info->topLeftX)-baseAddr;
337    nresults[8] = (size_t)&(info->topLeftY)-baseAddr;
338    nresults[9] = (size_t)&(info->image)-baseAddr;
339    nresults[10] = (jlong)(uintptr_t)info; /* invisible glyph */
340    nresults[11] = (size_t)&(info->cellInfo)-baseAddr;
341    nresults[12] = (size_t)&(info->managed)-baseAddr;
342
343    (*env)->ReleasePrimitiveArrayCritical(env, results, nresults, 0);
344}
345
346JNIEXPORT TTLayoutTableCache* newLayoutTableCache() {
347  TTLayoutTableCache* ltc = calloc(1, sizeof(TTLayoutTableCache));
348  if (ltc) {
349    int i;
350    for(i=0;i<LAYOUTCACHE_ENTRIES;i++) {
351      ltc->entries[i].len = -1;
352    }
353    ltc->entries[0].tag = GDEF_TAG;
354    ltc->entries[1].tag = GPOS_TAG;
355    ltc->entries[2].tag = GSUB_TAG;
356    ltc->entries[3].tag = HEAD_TAG;
357    ltc->entries[4].tag = KERN_TAG;
358    ltc->entries[5].tag = MORT_TAG;
359    ltc->entries[6].tag = MORX_TAG;
360  }
361  return ltc;
362}
363
364JNIEXPORT void freeLayoutTableCache(TTLayoutTableCache* ltc) {
365  if (ltc) {
366    int i;
367    for(i=0;i<LAYOUTCACHE_ENTRIES;i++) {
368      if(ltc->entries[i].ptr) free (ltc->entries[i].ptr);
369    }
370    if (ltc->kernPairs) free(ltc->kernPairs);
371    free(ltc);
372  }
373}
374