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 |
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 |
64 | Java_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 | |
81 | JNIEXPORT jlong JNICALL |
82 | Java_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 |
149 | XGetFontProperty(xFont,XA_ITALIC_ANGLE, &angle); |
150 | */ |
151 | |
152 | /* return (jint)angle; */ |
153 | /* } */ |
154 | |
155 | JNIEXPORT jboolean JNICALL |
156 | Java_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 | |
179 | JNIEXPORT jboolean JNICALL |
180 | Java_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. |
208 | JNIEXPORT jint JNICALL |
209 | Java_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 | |
226 | JNIEXPORT jint JNICALL |
227 | Java_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 | |
238 | JNIEXPORT jfloat JNICALL |
239 | Java_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 | |
282 | JNIEXPORT jlong JNICALL |
283 | Java_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 | |
308 | JNIEXPORT jlong JNICALL |
309 | Java_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 | |
334 | JNIEXPORT 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 | |