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