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
Java_sun_font_NullFontScaler_getNullScalerContext(JNIEnv * env,jclass scalerClass)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 
isNullScalerContext(void * context)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  */
Java_sun_font_NullFontScaler_getGlyphImage(JNIEnv * env,jobject scaler,jlong pContext,jint glyphCode)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 
initFontIDs(JNIEnv * env)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.f2dCharToVariationGlyphMID =
148          (*env)->GetMethodID(env, tmpClass, "charToVariationGlyph", "(II)I"));
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 
161      CHECK_NULL(tmpClass = (*env)->FindClass(env, "sun/font/PhysicalStrike"));
162      CHECK_NULL(sunFontIDs.getGlyphMetricsMID =
163          (*env)->GetMethodID(env, tmpClass, "getGlyphMetrics",
164                              "(I)Ljava/awt/geom/Point2D$Float;"));
165      CHECK_NULL(sunFontIDs.getGlyphPointMID =
166          (*env)->GetMethodID(env, tmpClass, "getGlyphPoint",
167                              "(II)Ljava/awt/geom/Point2D$Float;"));
168      CHECK_NULL(sunFontIDs.adjustPointMID =
169          (*env)->GetMethodID(env, tmpClass, "adjustPoint",
170                              "(Ljava/awt/geom/Point2D$Float;)V"));
171      CHECK_NULL(sunFontIDs.pScalerContextFID =
172          (*env)->GetFieldID(env, tmpClass, "pScalerContext", "J"));
173 
174      CHECK_NULL(tmpClass = (*env)->FindClass(env, "sun/font/GlyphList"));
175      CHECK_NULL(sunFontIDs.glyphListX =
176          (*env)->GetFieldID(env, tmpClass, "x", "F"));
177      CHECK_NULL(sunFontIDs.glyphListY =
178          (*env)->GetFieldID(env, tmpClass, "y", "F"));
179      CHECK_NULL(sunFontIDs.glyphListLen =
180          (*env)->GetFieldID(env, tmpClass, "len", "I"));
181      CHECK_NULL(sunFontIDs.glyphImages =
182          (*env)->GetFieldID(env, tmpClass, "images", "[J"));
183      CHECK_NULL(sunFontIDs.glyphListUsePos =
184          (*env)->GetFieldID(env, tmpClass, "usePositions", "Z"));
185      CHECK_NULL(sunFontIDs.glyphListPos =
186          (*env)->GetFieldID(env, tmpClass, "positions", "[F"));
187      CHECK_NULL(sunFontIDs.lcdRGBOrder =
188          (*env)->GetFieldID(env, tmpClass, "lcdRGBOrder", "Z"));
189      CHECK_NULL(sunFontIDs.lcdSubPixPos =
190          (*env)->GetFieldID(env, tmpClass, "lcdSubPixPos", "Z"));
191 
192      initLCDGammaTables();
193 
194      initialisedFontIDs = 1;
195 }
196 
197 JNIEXPORT void JNICALL
Java_sun_font_SunFontManager_initIDs(JNIEnv * env,jclass cls)198 Java_sun_font_SunFontManager_initIDs
199     (JNIEnv *env, jclass cls) {
200 
201     initFontIDs(env);
202 }
203 
getSunFontIDs(JNIEnv * env)204 JNIEXPORT FontManagerNativeIDs getSunFontIDs(JNIEnv *env) {
205 
206     initFontIDs(env);
207     return sunFontIDs;
208 }
209 
210 /*
211  * Class:     sun_font_StrikeCache
212  * Method:    freeIntPointer
213  * Signature: (I)V
214  */
Java_sun_font_StrikeCache_freeIntPointer(JNIEnv * env,jclass cacheClass,jint ptr)215 JNIEXPORT void JNICALL Java_sun_font_StrikeCache_freeIntPointer
216     (JNIEnv *env, jclass cacheClass, jint ptr) {
217 
218     /* Note this is used for freeing a glyph which was allocated
219      * but never placed into the glyph cache. The caller holds the
220      * only reference, therefore it is unnecessary to invalidate any
221      * accelerated glyph cache cells as we do in freeInt/LongMemory().
222      */
223     if (ptr != 0) {
224         free((void*)((intptr_t)ptr));
225     }
226 }
227 
228 /*
229  * Class:     sun_font_StrikeCache
230  * Method:    freeLongPointer
231  * Signature: (J)V
232  */
Java_sun_font_StrikeCache_freeLongPointer(JNIEnv * env,jclass cacheClass,jlong ptr)233 JNIEXPORT void JNICALL Java_sun_font_StrikeCache_freeLongPointer
234     (JNIEnv *env, jclass cacheClass, jlong ptr) {
235 
236     /* Note this is used for freeing a glyph which was allocated
237      * but never placed into the glyph cache. The caller holds the
238      * only reference, therefore it is unnecessary to invalidate any
239      * accelerated glyph cache cells as we do in freeInt/LongMemory().
240      */
241     if (ptr != 0L) {
242         free(jlong_to_ptr(ptr));
243     }
244 }
245 
246 /*
247  * Class:     sun_font_StrikeCache
248  * Method:    freeIntMemory
249  * Signature: ([I)V
250  */
Java_sun_font_StrikeCache_freeIntMemory(JNIEnv * env,jclass cacheClass,jintArray jmemArray,jlong pContext)251 JNIEXPORT void JNICALL Java_sun_font_StrikeCache_freeIntMemory
252     (JNIEnv *env, jclass cacheClass, jintArray jmemArray, jlong pContext) {
253 
254     int len = (*env)->GetArrayLength(env, jmemArray);
255     jint* ptrs =
256         (jint*)(*env)->GetPrimitiveArrayCritical(env, jmemArray, NULL);
257     int i;
258 
259     if (ptrs) {
260         for (i=0; i< len; i++) {
261             if (ptrs[i] != 0) {
262                 GlyphInfo *ginfo = (GlyphInfo *)((intptr_t)ptrs[i]);
263                 if (ginfo->cellInfo != NULL &&
264                     ginfo->managed == MANAGED_GLYPH) {
265                     // invalidate this glyph's accelerated cache cell
266                     AccelGlyphCache_RemoveAllCellInfos(ginfo);
267                 }
268                 free(ginfo);
269             }
270         }
271         (*env)->ReleasePrimitiveArrayCritical(env, jmemArray, ptrs, JNI_ABORT);
272     }
273     if (!isNullScalerContext(jlong_to_ptr(pContext))) {
274         free(jlong_to_ptr(pContext));
275     }
276 }
277 
278 /*
279  * Class:     sun_font_StrikeCache
280  * Method:    freeLongMemory
281  * Signature: ([J)V
282  */
Java_sun_font_StrikeCache_freeLongMemory(JNIEnv * env,jclass cacheClass,jlongArray jmemArray,jlong pContext)283 JNIEXPORT void JNICALL Java_sun_font_StrikeCache_freeLongMemory
284     (JNIEnv *env, jclass cacheClass, jlongArray jmemArray, jlong pContext) {
285 
286     int len = (*env)->GetArrayLength(env, jmemArray);
287     jlong* ptrs =
288         (jlong*)(*env)->GetPrimitiveArrayCritical(env, jmemArray, NULL);
289     int i;
290 
291     if (ptrs) {
292         for (i=0; i< len; i++) {
293             if (ptrs[i] != 0L) {
294                 GlyphInfo *ginfo = (GlyphInfo *) jlong_to_ptr(ptrs[i]);
295                 if (ginfo->cellInfo != NULL &&
296                     ginfo->managed == MANAGED_GLYPH) {
297                     AccelGlyphCache_RemoveAllCellInfos(ginfo);
298                 }
299                 free((void*)ginfo);
300             }
301         }
302         (*env)->ReleasePrimitiveArrayCritical(env, jmemArray, ptrs, JNI_ABORT);
303     }
304     if (!isNullScalerContext(jlong_to_ptr(pContext))) {
305         free(jlong_to_ptr(pContext));
306     }
307 }
308 
309 JNIEXPORT void JNICALL
Java_sun_font_StrikeCache_getGlyphCacheDescription(JNIEnv * env,jclass cls,jlongArray results)310 Java_sun_font_StrikeCache_getGlyphCacheDescription
311   (JNIEnv *env, jclass cls, jlongArray results) {
312 
313     jlong* nresults;
314     GlyphInfo *info;
315     size_t baseAddr;
316 
317     if ((*env)->GetArrayLength(env, results) < 13) {
318         return;
319     }
320 
321     nresults = (jlong*)(*env)->GetPrimitiveArrayCritical(env, results, NULL);
322     if (nresults == NULL) {
323         return;
324     }
325     info = (GlyphInfo*) calloc(1, sizeof(GlyphInfo));
326     if (info == NULL) {
327         (*env)->ReleasePrimitiveArrayCritical(env, results, nresults, 0);
328         return;
329     }
330     baseAddr = (size_t)info;
331     nresults[0] = sizeof(void*);
332     nresults[1] = sizeof(GlyphInfo);
333     nresults[2] = 0;
334     nresults[3] = (size_t)&(info->advanceY)-baseAddr;
335     nresults[4] = (size_t)&(info->width)-baseAddr;
336     nresults[5] = (size_t)&(info->height)-baseAddr;
337     nresults[6] = (size_t)&(info->rowBytes)-baseAddr;
338     nresults[7] = (size_t)&(info->topLeftX)-baseAddr;
339     nresults[8] = (size_t)&(info->topLeftY)-baseAddr;
340     nresults[9] = (size_t)&(info->image)-baseAddr;
341     nresults[10] = (jlong)(uintptr_t)info; /* invisible glyph */
342     nresults[11] = (size_t)&(info->cellInfo)-baseAddr;
343     nresults[12] = (size_t)&(info->managed)-baseAddr;
344 
345     (*env)->ReleasePrimitiveArrayCritical(env, results, nresults, 0);
346 }
347