1 /*
2  * Copyright (c) 2003, 2012, 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 /*
27  * Important note : All AWTxxx functions are defined in font.h.
28  * These were added to remove the dependency of this file on X11.
29  * These functions are used to perform X11 operations and should
30  * be "stubbed out" in environments that do not support X11.
31  * The implementation of these functions has been moved from this file
32  * into X11FontScaler_md.c, which is compiled into another library.
33  */
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <ctype.h>
37 #include <sys/utsname.h>
38 
39 #include <jni.h>
40 #include <jni_util.h>
41 
42 #include "sun_font_NativeFont.h"
43 #include "sun_font_NativeStrike.h"
44 #include "sun_font_NativeStrikeDisposer.h"
45 #include "sunfontids.h"
46 #include "fontscalerdefs.h"
47 #include "X11FontScaler.h"
48 
49 JNIEXPORT void JNICALL
Java_sun_font_NativeStrikeDisposer_freeNativeScalerContext(JNIEnv * env,jobject disposer,jlong pScalerContext)50     Java_sun_font_NativeStrikeDisposer_freeNativeScalerContext
51     (JNIEnv *env, jobject disposer, jlong pScalerContext) {
52 
53     NativeScalerContext *context = (NativeScalerContext*)pScalerContext;
54 
55     if (context != NULL) {
56         if (context->xFont != NULL) {
57             AWTFreeFont(context->xFont);
58         }
59         free(context);
60     }
61 }
62 
63 JNIEXPORT jlong JNICALL
Java_sun_font_NativeStrike_createNullScalerContext(JNIEnv * env,jobject strike)64 Java_sun_font_NativeStrike_createNullScalerContext
65     (JNIEnv *env, jobject strike) {
66 
67    NativeScalerContext *context =
68        (NativeScalerContext*)malloc(sizeof(NativeScalerContext));
69    context->xFont = NULL;
70    context->minGlyph = 0;
71    context->maxGlyph = 0;
72    context->numGlyphs = 0;
73    context->defaultGlyph = 0;
74    context->ptSize = NO_POINTSIZE;
75    return (jlong)(uintptr_t)context;
76 }
77 
78 JNIEXPORT jlong JNICALL
Java_sun_font_NativeStrike_createScalerContext(JNIEnv * env,jobject strike,jbyteArray xlfdBytes,jint ptSize,jdouble scale)79 Java_sun_font_NativeStrike_createScalerContext
80     (JNIEnv *env, jobject strike, jbyteArray xlfdBytes,
81      jint ptSize, jdouble scale) {
82 
83     NativeScalerContext *context;
84     int len = (*env)->GetArrayLength(env, xlfdBytes);
85 
86     char* xlfd = (char*)malloc(len+1);
87 
88     if (xlfd == NULL) {
89         return (jlong)(uintptr_t)0L;
90     }
91 
92     (*env)->GetByteArrayRegion(env, xlfdBytes, 0, len, (jbyte*)xlfd);
93     xlfd[len] = '\0';
94     context = (NativeScalerContext*)malloc(sizeof(NativeScalerContext));
95 
96     AWTLoadFont (xlfd, &(context->xFont));
97     free(xlfd);
98 
99     if (context->xFont == NULL) {   /* NULL means couldn't find the font */
100         free(context);
101         context = NULL;
102     } else {
103         /* numGlyphs is an estimate : X11 doesn't provide a quick way to
104          * discover which glyphs are valid: just the range that contains all
105          * the valid glyphs, and this range may have holes.
106          */
107         context->minGlyph = (AWTFontMinByte1(context->xFont) << 8) +
108             AWTFontMinCharOrByte2(context->xFont);
109         context->maxGlyph = (AWTFontMaxByte1(context->xFont) << 8) +
110             AWTFontMaxCharOrByte2(context->xFont);
111         context->numGlyphs = context->maxGlyph - context->minGlyph + 1;
112         context->defaultGlyph = AWTFontDefaultChar(context->xFont);
113         /* Sometimes the default_char field of the XFontStruct isn't
114          * initialized to anything, so it can be a large number. So,
115          * check to see if its less than the largest possible value
116          * and if so, then use it. Otherwise, just use the minGlyph.
117          */
118         if (context->defaultGlyph < context->minGlyph ||
119             context->defaultGlyph > context->maxGlyph) {
120             context->defaultGlyph = context->minGlyph;
121         }
122         context->ptSize = ptSize;
123         context->scale = scale;
124     }
125 
126     /*
127      * REMIND: freeing of native resources? XID, XFontStruct etc??
128      */
129     return (jlong)(uintptr_t)context;
130 }
131 
132 
133 /* JNIEXPORT jint JNICALL */
134 /* Java_sun_font_NativeFont_getItalicAngle */
135 /*     (JNIEnv *env, jobject font) { */
136 
137 /*     UInt32 angle; */
138 /*     AWTGetFontItalicAngle(xFont, &angle); */
139 /*X11 reports italic angle as 1/64ths of a degree, relative to 3 o'clock
140  * with anti-clockwise being the +ve rotation direction.
141  * We return
142 XGetFontProperty(xFont,XA_ITALIC_ANGLE, &angle);
143 */
144 
145 /*     return (jint)angle; */
146 /* } */
147 
148 JNIEXPORT jboolean JNICALL
Java_sun_font_NativeFont_fontExists(JNIEnv * env,jclass fontClass,jbyteArray xlfdBytes)149 Java_sun_font_NativeFont_fontExists
150     (JNIEnv *env, jclass fontClass, jbyteArray xlfdBytes) {
151 
152     int count = 0;
153     int len = (*env)->GetArrayLength(env, xlfdBytes);
154     char* xlfd = (char*)malloc(len+1);
155 
156     if (xlfd == NULL) {
157         return JNI_FALSE;
158     }
159 
160     (*env)->GetByteArrayRegion(env, xlfdBytes, 0, len, (jbyte*)xlfd);
161     xlfd[len] = '\0';
162 
163     count = AWTCountFonts(xlfd);
164     free(xlfd);
165     if (count > 0) {
166         return JNI_TRUE;
167     } else {
168         return JNI_FALSE;
169     }
170 }
171 
172 JNIEXPORT jboolean JNICALL
Java_sun_font_NativeFont_haveBitmapFonts(JNIEnv * env,jclass fontClass,jbyteArray xlfdBytes)173 Java_sun_font_NativeFont_haveBitmapFonts
174     (JNIEnv *env, jclass fontClass, jbyteArray xlfdBytes) {
175 
176     int count = 0;
177     int len = (*env)->GetArrayLength(env, xlfdBytes);
178     char* xlfd = (char*)malloc(len+1);
179 
180     if (xlfd == NULL) {
181         return JNI_FALSE;
182     }
183 
184     (*env)->GetByteArrayRegion(env, xlfdBytes, 0, len, (jbyte*)xlfd);
185     xlfd[len] = '\0';
186 
187     count = AWTCountFonts(xlfd);
188     free(xlfd);
189     if (count > 2) {
190         return JNI_TRUE;
191     } else {
192         return JNI_FALSE;
193     }
194 }
195 
196 // CountGlyphs doubles as way of getting a native font reference
197 // and telling if its valid. So far as I can tell GenerateImage etc
198 // just return if this "initialisation method" hasn't been called.
199 // So clients of this class need to call CountGlyphs() right after
200 // construction to be safe.
201 JNIEXPORT jint JNICALL
Java_sun_font_NativeFont_countGlyphs(JNIEnv * env,jobject font,jbyteArray xlfdBytes,jint ptSize)202 Java_sun_font_NativeFont_countGlyphs
203     (JNIEnv *env, jobject font, jbyteArray xlfdBytes, jint ptSize) {
204 
205     NativeScalerContext *context = (NativeScalerContext*)
206         Java_sun_font_NativeStrike_createScalerContext
207         (env, NULL, xlfdBytes, ptSize, 1);
208 
209     if (context == NULL) {
210         return 0;
211     } else {
212         int numGlyphs = context->numGlyphs;
213         AWTFreeFont(context->xFont);
214         free(context);
215         return numGlyphs;
216     }
217 }
218 
219 JNIEXPORT jint JNICALL
Java_sun_font_NativeStrike_getMaxGlyph(JNIEnv * env,jobject strike,jlong pScalerContext)220 Java_sun_font_NativeStrike_getMaxGlyph
221     (JNIEnv *env, jobject strike, jlong pScalerContext) {
222 
223     NativeScalerContext *context = (NativeScalerContext*)pScalerContext;
224     if (context == NULL) {
225         return (jint)0;
226     } else {
227         return (jint)context->maxGlyph+1;
228     }
229 }
230 
231 JNIEXPORT jfloat JNICALL
Java_sun_font_NativeFont_getGlyphAdvance(JNIEnv * env,jobject font2D,jlong pScalerContext,jint glyphCode)232 Java_sun_font_NativeFont_getGlyphAdvance
233    (JNIEnv *env, jobject font2D, jlong pScalerContext, jint glyphCode) {
234 
235     NativeScalerContext *context = (NativeScalerContext*)pScalerContext;
236     AWTFont xFont = (AWTFont)context->xFont;
237     AWTChar xcs = NULL;
238     jfloat advance = 0.0f;
239 
240     if (xFont == NULL || context->ptSize == NO_POINTSIZE) {
241         return advance;
242     }
243 
244     if (glyphCode < context->minGlyph || glyphCode > context->maxGlyph) {
245         glyphCode = context->defaultGlyph;
246     }
247 
248     /* If number of glyphs is 256 or less, the metrics are
249      * stored correctly in the XFontStruct for each
250      * character. If the # characters is more (double byte
251      * case), then these metrics seem flaky and there's no
252      * way to determine if they have been set or not.
253      */
254     if ((context->maxGlyph <= 256) && (AWTFontPerChar(xFont, 0) != NULL)) {
255         xcs = AWTFontPerChar(xFont, glyphCode - context->minGlyph);
256         advance = AWTCharAdvance(xcs);
257     } else {
258         int direction, ascent, descent;
259         AWTChar2b xChar;
260 
261         xChar.byte1 = (unsigned char) (glyphCode >> 8);
262         xChar.byte2 = (unsigned char) glyphCode;
263         AWTFontTextExtents16(xFont, &xChar, &xcs);
264         advance = AWTCharAdvance(xcs);
265         AWTFreeChar(xcs);
266     }
267     return (jfloat)(advance/context->scale);
268 }
269 
270 JNIEXPORT jlong JNICALL
Java_sun_font_NativeFont_getGlyphImageNoDefault(JNIEnv * env,jobject font2D,jlong pScalerContext,jint glyphCode)271 Java_sun_font_NativeFont_getGlyphImageNoDefault
272     (JNIEnv *env, jobject font2D, jlong pScalerContext, jint glyphCode) {
273 
274     NativeScalerContext *context = (NativeScalerContext*)pScalerContext;
275     AWTFont xFont = context->xFont;
276     AWTChar2b xChar;
277 
278     if (xFont == NULL || context->ptSize == NO_POINTSIZE) {
279         return (jlong)0;
280     }
281 
282     if (glyphCode < context->minGlyph || glyphCode > context->maxGlyph) {
283         return (jlong)0;
284     }
285 
286     xChar.byte1 = (unsigned char)(glyphCode >> 8);
287     xChar.byte2 = (unsigned char)glyphCode;
288     return AWTFontGenerateImage(xFont, &xChar);
289 }
290 
291 JNIEXPORT jlong JNICALL
Java_sun_font_NativeFont_getGlyphImage(JNIEnv * env,jobject font2D,jlong pScalerContext,jint glyphCode)292 Java_sun_font_NativeFont_getGlyphImage
293     (JNIEnv *env, jobject font2D, jlong pScalerContext, jint glyphCode) {
294 
295     NativeScalerContext *context = (NativeScalerContext*)pScalerContext;
296     AWTFont xFont = context->xFont;
297     AWTChar2b xChar;
298 
299     if (xFont == NULL || context->ptSize == NO_POINTSIZE) {
300         return (jlong)0;
301     }
302 
303     if (glyphCode < context->minGlyph || glyphCode > context->maxGlyph) {
304         glyphCode = context->defaultGlyph;
305     }
306 
307     xChar.byte1 = (unsigned char)(glyphCode >> 8);
308     xChar.byte2 = (unsigned char)glyphCode;
309     return AWTFontGenerateImage(xFont, &xChar);
310 }
311 
312 JNIEXPORT jobject JNICALL
Java_sun_font_NativeFont_getFontMetrics(JNIEnv * env,jobject font2D,jlong pScalerContext)313   Java_sun_font_NativeFont_getFontMetrics
314     (JNIEnv *env, jobject font2D, jlong pScalerContext) {
315 
316     NativeScalerContext *context = (NativeScalerContext*)pScalerContext;
317     AWTFont xFont = (AWTFont)context->xFont;
318     jfloat j0=0, j1=1, ay=j0, dy=j0, mx=j0;
319     jobject metrics;
320 
321     if (xFont == NULL) {
322         return NULL;
323     }
324 
325     /* the commented out lines are the old 1.4.x behaviour which used max
326      * bounds instead of the font's designed ascent/descent */
327 /*   ay =  (jfloat)-AWTCharAscent(AWTFontMaxBounds(xFont)); */
328 /*   dy =  (jfloat)AWTCharDescent(AWTFontMaxBounds(xFont)); */
329 
330     ay = (jfloat)-AWTFontAscent(xFont);
331     dy = (jfloat)AWTFontDescent(xFont);
332     mx = (jfloat)AWTCharAdvance(AWTFontMaxBounds(xFont));
333 
334     /* ascent : no need to set ascentX - it will be zero
335      * descent : no need to set descentX - it will be zero
336      * baseline :  old releases "made up" a number and also seemed to
337      * make it up for "X" and set "Y" to 0.
338      * leadingX : no need to set leadingX - it will be zero.
339      * leadingY : made-up number, but being compatible with what 1.4.x did
340      * advance : no need to set yMaxLinearAdvanceWidth - it will be zero.
341      */
342     metrics = (*env)->NewObject(env, sunFontIDs.strikeMetricsClass,
343                                 sunFontIDs.strikeMetricsCtr,
344                                 j0, ay, j0, dy, j1, j0, j0, j1, mx, j0);
345 /*      printf("X11 asc=%f dsc=%f adv=%f scale=%f\n", */
346 /*          ay, dy, mx, (float)context->scale); */
347     return metrics;
348 }
349