1 | /* |
2 | * Copyright (c) 1998, 2018, 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 | #if defined(__linux__) |
27 | #include <string.h> |
28 | #endif /* __linux__ */ |
29 | #include <stdio.h> |
30 | #include <stdlib.h> |
31 | #include <strings.h> |
32 | #include <sys/types.h> |
33 | #include <sys/stat.h> |
34 | #include <sys/mman.h> |
35 | #include <fcntl.h> |
36 | #include <unistd.h> |
37 | #ifdef __solaris__ |
38 | #include <sys/systeminfo.h> |
39 | #endif |
40 | |
41 | #include <jni.h> |
42 | #include <jni_util.h> |
43 | #include <jvm_md.h> |
44 | #include <sizecalc.h> |
45 | #ifndef HEADLESS |
46 | #include <X11/Xlib.h> |
47 | #include <awt.h> |
48 | #else |
49 | /* locks ought to be included from awt.h */ |
50 | #define AWT_LOCK() |
51 | #define AWT_UNLOCK() |
52 | #endif /* !HEADLESS */ |
53 | |
54 | #if defined(__linux__) && !defined(MAP_FAILED) |
55 | #define MAP_FAILED ((caddr_t)-1) |
56 | #endif |
57 | |
58 | #ifndef HEADLESS |
59 | extern Display *awt_display; |
60 | #endif /* !HEADLESS */ |
61 | |
62 | #define FONTCONFIG_DLL_VERSIONED VERSIONED_JNI_LIB_NAME("fontconfig", "1") |
63 | #define FONTCONFIG_DLL JNI_LIB_NAME("fontconfig") |
64 | |
65 | #define MAXFDIRS 512 /* Max number of directories that contain fonts */ |
66 | |
67 | #if defined(__solaris__) |
68 | /* |
69 | * This can be set in the makefile to "/usr/X11" if so desired. |
70 | */ |
71 | #ifndef OPENWINHOMELIB |
72 | #define OPENWINHOMELIB "/usr/openwin/lib/" |
73 | #endif |
74 | |
75 | /* This is all known Solaris X11 directories on Solaris 8, 9 and 10. |
76 | * It is ordered to give precedence to TrueType directories. |
77 | * It is needed if fontconfig is not installed or configured properly. |
78 | */ |
79 | static char *fullSolarisFontPath[] = { |
80 | OPENWINHOMELIB "X11/fonts/TrueType" , |
81 | OPENWINHOMELIB "locale/euro_fonts/X11/fonts/TrueType" , |
82 | OPENWINHOMELIB "locale/iso_8859_2/X11/fonts/TrueType" , |
83 | OPENWINHOMELIB "locale/iso_8859_5/X11/fonts/TrueType" , |
84 | OPENWINHOMELIB "locale/iso_8859_7/X11/fonts/TrueType" , |
85 | OPENWINHOMELIB "locale/iso_8859_8/X11/fonts/TrueType" , |
86 | OPENWINHOMELIB "locale/iso_8859_9/X11/fonts/TrueType" , |
87 | OPENWINHOMELIB "locale/iso_8859_13/X11/fonts/TrueType" , |
88 | OPENWINHOMELIB "locale/iso_8859_15/X11/fonts/TrueType" , |
89 | OPENWINHOMELIB "locale/ar/X11/fonts/TrueType" , |
90 | OPENWINHOMELIB "locale/hi_IN.UTF-8/X11/fonts/TrueType" , |
91 | OPENWINHOMELIB "locale/ja/X11/fonts/TT" , |
92 | OPENWINHOMELIB "locale/ko/X11/fonts/TrueType" , |
93 | OPENWINHOMELIB "locale/ko.UTF-8/X11/fonts/TrueType" , |
94 | OPENWINHOMELIB "locale/KOI8-R/X11/fonts/TrueType" , |
95 | OPENWINHOMELIB "locale/ru.ansi-1251/X11/fonts/TrueType" , |
96 | OPENWINHOMELIB "locale/th_TH/X11/fonts/TrueType" , |
97 | OPENWINHOMELIB "locale/zh_TW/X11/fonts/TrueType" , |
98 | OPENWINHOMELIB "locale/zh_TW.BIG5/X11/fonts/TT" , |
99 | OPENWINHOMELIB "locale/zh_HK.BIG5HK/X11/fonts/TT" , |
100 | OPENWINHOMELIB "locale/zh_CN.GB18030/X11/fonts/TrueType" , |
101 | OPENWINHOMELIB "locale/zh/X11/fonts/TrueType" , |
102 | OPENWINHOMELIB "locale/zh.GBK/X11/fonts/TrueType" , |
103 | OPENWINHOMELIB "X11/fonts/Type1" , |
104 | OPENWINHOMELIB "X11/fonts/Type1/sun" , |
105 | OPENWINHOMELIB "X11/fonts/Type1/sun/outline" , |
106 | OPENWINHOMELIB "locale/iso_8859_2/X11/fonts/Type1" , |
107 | OPENWINHOMELIB "locale/iso_8859_4/X11/fonts/Type1" , |
108 | OPENWINHOMELIB "locale/iso_8859_5/X11/fonts/Type1" , |
109 | OPENWINHOMELIB "locale/iso_8859_7/X11/fonts/Type1" , |
110 | OPENWINHOMELIB "locale/iso_8859_8/X11/fonts/Type1" , |
111 | OPENWINHOMELIB "locale/iso_8859_9/X11/fonts/Type1" , |
112 | OPENWINHOMELIB "locale/iso_8859_13/X11/fonts/Type1" , |
113 | OPENWINHOMELIB "locale/ar/X11/fonts/Type1" , |
114 | NULL, /* terminates the list */ |
115 | }; |
116 | |
117 | #elif defined( __linux__) |
118 | /* All the known interesting locations we have discovered on |
119 | * various flavors of Linux |
120 | */ |
121 | static char *fullLinuxFontPath[] = { |
122 | "/usr/X11R6/lib/X11/fonts/TrueType" , /* RH 7.1+ */ |
123 | "/usr/X11R6/lib/X11/fonts/truetype" , /* SuSE */ |
124 | "/usr/X11R6/lib/X11/fonts/tt" , |
125 | "/usr/X11R6/lib/X11/fonts/TTF" , |
126 | "/usr/X11R6/lib/X11/fonts/OTF" , /* RH 9.0 (but empty!) */ |
127 | "/usr/share/fonts/ja/TrueType" , /* RH 7.2+ */ |
128 | "/usr/share/fonts/truetype" , |
129 | "/usr/share/fonts/ko/TrueType" , /* RH 9.0 */ |
130 | "/usr/share/fonts/zh_CN/TrueType" , /* RH 9.0 */ |
131 | "/usr/share/fonts/zh_TW/TrueType" , /* RH 9.0 */ |
132 | "/var/lib/defoma/x-ttcidfont-conf.d/dirs/TrueType" , /* Debian */ |
133 | "/usr/X11R6/lib/X11/fonts/Type1" , |
134 | "/usr/share/fonts/default/Type1" , /* RH 9.0 */ |
135 | NULL, /* terminates the list */ |
136 | }; |
137 | #elif defined(_AIX) |
138 | static char *fullAixFontPath[] = { |
139 | "/usr/lpp/X11/lib/X11/fonts/Type1" , /* from X11.fnt.iso_T1 */ |
140 | "/usr/lpp/X11/lib/X11/fonts/TrueType" , /* from X11.fnt.ucs.ttf */ |
141 | NULL, /* terminates the list */ |
142 | }; |
143 | #endif |
144 | |
145 | static char **getFontConfigLocations(); |
146 | |
147 | typedef struct { |
148 | const char *name[MAXFDIRS]; |
149 | int num; |
150 | } fDirRecord, *fDirRecordPtr; |
151 | |
152 | #ifndef HEADLESS |
153 | |
154 | /* |
155 | * Returns True if display is local, False of it's remote. |
156 | */ |
157 | jboolean isDisplayLocal(JNIEnv *env) { |
158 | static jboolean isLocal = False; |
159 | static jboolean isLocalSet = False; |
160 | jboolean ret; |
161 | |
162 | if (! isLocalSet) { |
163 | jclass geCls = (*env)->FindClass(env, "java/awt/GraphicsEnvironment" ); |
164 | CHECK_NULL_RETURN(geCls, JNI_FALSE); |
165 | jmethodID getLocalGE = (*env)->GetStaticMethodID(env, geCls, |
166 | "getLocalGraphicsEnvironment" , |
167 | "()Ljava/awt/GraphicsEnvironment;" ); |
168 | CHECK_NULL_RETURN(getLocalGE, JNI_FALSE); |
169 | jobject ge = (*env)->CallStaticObjectMethod(env, geCls, getLocalGE); |
170 | JNU_CHECK_EXCEPTION_RETURN(env, JNI_FALSE); |
171 | |
172 | jclass sgeCls = (*env)->FindClass(env, |
173 | "sun/java2d/SunGraphicsEnvironment" ); |
174 | CHECK_NULL_RETURN(sgeCls, JNI_FALSE); |
175 | if ((*env)->IsInstanceOf(env, ge, sgeCls)) { |
176 | jmethodID isDisplayLocal = (*env)->GetMethodID(env, sgeCls, |
177 | "isDisplayLocal" , |
178 | "()Z" ); |
179 | JNU_CHECK_EXCEPTION_RETURN(env, JNI_FALSE); |
180 | isLocal = (*env)->CallBooleanMethod(env, ge, isDisplayLocal); |
181 | JNU_CHECK_EXCEPTION_RETURN(env, JNI_FALSE); |
182 | } else { |
183 | isLocal = True; |
184 | } |
185 | isLocalSet = True; |
186 | } |
187 | |
188 | return isLocal; |
189 | } |
190 | |
191 | static void AddFontsToX11FontPath ( fDirRecord *fDirP ) |
192 | { |
193 | char *onePath; |
194 | int index, nPaths; |
195 | int origNumPaths, length; |
196 | int origIndex; |
197 | int totalDirCount; |
198 | char **origFontPath; |
199 | char **tempFontPath; |
200 | int doNotAppend; |
201 | int *appendDirList; |
202 | char **newFontPath; |
203 | int err, compareLength; |
204 | char fontDirPath[512]; |
205 | int dirFile; |
206 | |
207 | doNotAppend = 0; |
208 | |
209 | if ( fDirP->num == 0 ) return; |
210 | |
211 | appendDirList = SAFE_SIZE_ARRAY_ALLOC(malloc, fDirP->num, sizeof ( int )); |
212 | if ( appendDirList == NULL ) { |
213 | return; /* if it fails we cannot do much */ |
214 | } |
215 | |
216 | origFontPath = XGetFontPath ( awt_display, &nPaths ); |
217 | |
218 | totalDirCount = nPaths; |
219 | origNumPaths = nPaths; |
220 | tempFontPath = origFontPath; |
221 | |
222 | |
223 | for (index = 0; index < fDirP->num; index++ ) { |
224 | |
225 | doNotAppend = 0; |
226 | |
227 | tempFontPath = origFontPath; |
228 | for ( origIndex = 0; origIndex < nPaths; origIndex++ ) { |
229 | |
230 | onePath = *tempFontPath; |
231 | |
232 | compareLength = strlen ( onePath ); |
233 | if ( onePath[compareLength -1] == '/' ) |
234 | compareLength--; |
235 | |
236 | /* there is a slash at the end of every solaris X11 font path name */ |
237 | if ( strncmp ( onePath, fDirP->name[index], compareLength ) == 0 ) { |
238 | doNotAppend = 1; |
239 | break; |
240 | } |
241 | tempFontPath++; |
242 | } |
243 | |
244 | appendDirList[index] = 0; |
245 | if ( doNotAppend == 0 ) { |
246 | snprintf(fontDirPath, sizeof(fontDirPath), "%s/fonts.dir" , fDirP->name[index]); |
247 | fontDirPath[sizeof(fontDirPath) - 1] = '\0'; |
248 | dirFile = open ( fontDirPath, O_RDONLY, 0 ); |
249 | if ( dirFile == -1 ) { |
250 | doNotAppend = 1; |
251 | } else { |
252 | close ( dirFile ); |
253 | totalDirCount++; |
254 | appendDirList[index] = 1; |
255 | } |
256 | } |
257 | |
258 | } |
259 | |
260 | /* if no changes are required do not bother to do a setfontpath */ |
261 | if ( totalDirCount == nPaths ) { |
262 | free ( ( void *) appendDirList ); |
263 | XFreeFontPath ( origFontPath ); |
264 | return; |
265 | } |
266 | |
267 | |
268 | newFontPath = SAFE_SIZE_ARRAY_ALLOC(malloc, totalDirCount, sizeof(char *)); |
269 | /* if it fails free things and get out */ |
270 | if ( newFontPath == NULL ) { |
271 | free ( ( void *) appendDirList ); |
272 | XFreeFontPath ( origFontPath ); |
273 | return; |
274 | } |
275 | |
276 | for ( origIndex = 0; origIndex < nPaths; origIndex++ ) { |
277 | onePath = origFontPath[origIndex]; |
278 | newFontPath[origIndex] = onePath; |
279 | } |
280 | |
281 | /* now add the other font paths */ |
282 | |
283 | for (index = 0; index < fDirP->num; index++ ) { |
284 | |
285 | if ( appendDirList[index] == 1 ) { |
286 | |
287 | /* printf ( "Appending %s\n", fDirP->name[index] ); */ |
288 | |
289 | onePath = SAFE_SIZE_ARRAY_ALLOC(malloc, strlen (fDirP->name[index]) + 2, sizeof( char ) ); |
290 | if (onePath == NULL) { |
291 | free ( ( void *) appendDirList ); |
292 | |
293 | for ( index = origIndex; index < nPaths; index++ ) { |
294 | free( newFontPath[index] ); |
295 | } |
296 | |
297 | free( ( void *) newFontPath); |
298 | XFreeFontPath ( origFontPath ); |
299 | return; |
300 | } |
301 | strcpy ( onePath, fDirP->name[index] ); |
302 | strcat ( onePath, "/" ); |
303 | newFontPath[nPaths++] = onePath; |
304 | /* printf ( "The path to be appended is %s\n", onePath ); */ |
305 | } |
306 | } |
307 | |
308 | /* printf ( "The dir count = %d\n", totalDirCount ); */ |
309 | free ( ( void *) appendDirList ); |
310 | |
311 | XSetFontPath ( awt_display, newFontPath, totalDirCount ); |
312 | |
313 | for ( index = origNumPaths; index < totalDirCount; index++ ) { |
314 | free( newFontPath[index] ); |
315 | } |
316 | |
317 | free ( (void *) newFontPath ); |
318 | XFreeFontPath ( origFontPath ); |
319 | return; |
320 | } |
321 | #endif /* !HEADLESS */ |
322 | |
323 | |
324 | #ifndef HEADLESS |
325 | static char **getX11FontPath () |
326 | { |
327 | char **x11Path, **fontdirs; |
328 | int i, pos, slen, nPaths, numDirs; |
329 | |
330 | x11Path = XGetFontPath (awt_display, &nPaths); |
331 | |
332 | /* This isn't ever going to be perfect: the font path may contain |
333 | * much we aren't interested in, but the cost should be moderate |
334 | * Exclude all directories that contain the strings "Speedo","/F3/", |
335 | * "75dpi", "100dpi", "misc" or "bitmap", or don't begin with a "/", |
336 | * the last of which should exclude font servers. |
337 | * Also exclude the user specific ".gnome*" directories which |
338 | * aren't going to contain the system fonts we need. |
339 | * Hopefully we are left only with Type1 and TrueType directories. |
340 | * It doesn't matter much if there are extraneous directories, it'll just |
341 | * cost us a little wasted effort upstream. |
342 | */ |
343 | fontdirs = (char**)calloc(nPaths+1, sizeof(char*)); |
344 | pos = 0; |
345 | for (i=0; i < nPaths; i++) { |
346 | if (x11Path[i][0] != '/') { |
347 | continue; |
348 | } |
349 | if (strstr(x11Path[i], "/75dpi" ) != NULL) { |
350 | continue; |
351 | } |
352 | if (strstr(x11Path[i], "/100dpi" ) != NULL) { |
353 | continue; |
354 | } |
355 | if (strstr(x11Path[i], "/misc" ) != NULL) { |
356 | continue; |
357 | } |
358 | if (strstr(x11Path[i], "/Speedo" ) != NULL) { |
359 | continue; |
360 | } |
361 | if (strstr(x11Path[i], ".gnome" ) != NULL) { |
362 | continue; |
363 | } |
364 | #ifdef __solaris__ |
365 | if (strstr(x11Path[i], "/F3/" ) != NULL) { |
366 | continue; |
367 | } |
368 | if (strstr(x11Path[i], "bitmap" ) != NULL) { |
369 | continue; |
370 | } |
371 | #endif |
372 | fontdirs[pos] = strdup(x11Path[i]); |
373 | slen = strlen(fontdirs[pos]); |
374 | if (slen > 0 && fontdirs[pos][slen-1] == '/') { |
375 | fontdirs[pos][slen-1] = '\0'; /* null out trailing "/" */ |
376 | } |
377 | pos++; |
378 | } |
379 | |
380 | XFreeFontPath(x11Path); |
381 | if (pos == 0) { |
382 | free(fontdirs); |
383 | fontdirs = NULL; |
384 | } |
385 | return fontdirs; |
386 | } |
387 | |
388 | |
389 | #endif /* !HEADLESS */ |
390 | |
391 | #if defined(__linux__) |
392 | /* from awt_LoadLibrary.c */ |
393 | JNIEXPORT jboolean JNICALL AWTIsHeadless(); |
394 | #endif |
395 | |
396 | /* This eliminates duplicates, at a non-linear but acceptable cost |
397 | * since the lists are expected to be reasonably short, and then |
398 | * deletes references to non-existent directories, and returns |
399 | * a single path consisting of unique font directories. |
400 | */ |
401 | static char* mergePaths(char **p1, char **p2, char **p3, jboolean noType1) { |
402 | |
403 | int len1=0, len2=0, len3=0, totalLen=0, numDirs=0, |
404 | currLen, i, j, found, pathLen=0; |
405 | char **ptr, **fontdirs; |
406 | char *fontPath = NULL; |
407 | |
408 | if (p1 != NULL) { |
409 | ptr = p1; |
410 | while (*ptr++ != NULL) len1++; |
411 | } |
412 | if (p2 != NULL) { |
413 | ptr = p2; |
414 | |
415 | while (*ptr++ != NULL) len2++; |
416 | } |
417 | if (p3 != NULL) { |
418 | ptr = p3; |
419 | while (*ptr++ != NULL) len3++; |
420 | } |
421 | totalLen = len1+len2+len3; |
422 | fontdirs = (char**)calloc(totalLen, sizeof(char*)); |
423 | |
424 | for (i=0; i < len1; i++) { |
425 | if (noType1 && strstr(p1[i], "Type1" ) != NULL) { |
426 | continue; |
427 | } |
428 | fontdirs[numDirs++] = p1[i]; |
429 | } |
430 | |
431 | currLen = numDirs; /* only compare against previous path dirs */ |
432 | for (i=0; i < len2; i++) { |
433 | if (noType1 && strstr(p2[i], "Type1" ) != NULL) { |
434 | continue; |
435 | } |
436 | found = 0; |
437 | for (j=0; j < currLen; j++) { |
438 | if (strcmp(fontdirs[j], p2[i]) == 0) { |
439 | found = 1; |
440 | break; |
441 | } |
442 | } |
443 | if (!found) { |
444 | fontdirs[numDirs++] = p2[i]; |
445 | } |
446 | } |
447 | |
448 | currLen = numDirs; /* only compare against previous path dirs */ |
449 | for (i=0; i < len3; i++) { |
450 | if (noType1 && strstr(p3[i], "Type1" ) != NULL) { |
451 | continue; |
452 | } |
453 | found = 0; |
454 | for (j=0; j < currLen; j++) { |
455 | if (strcmp(fontdirs[j], p3[i]) == 0) { |
456 | found = 1; |
457 | break; |
458 | } |
459 | } |
460 | if (!found) { |
461 | fontdirs[numDirs++] = p3[i]; |
462 | } |
463 | } |
464 | |
465 | /* Now fontdirs contains unique dirs and numDirs records how many. |
466 | * What we don't know is if they all exist. On reflection I think |
467 | * this isn't an issue, so for now I will return all these locations, |
468 | * converted to one string */ |
469 | for (i=0; i<numDirs; i++) { |
470 | pathLen += (strlen(fontdirs[i]) + 1); |
471 | } |
472 | if (pathLen > 0 && (fontPath = malloc(pathLen))) { |
473 | *fontPath = '\0'; |
474 | for (i = 0; i<numDirs; i++) { |
475 | if (i != 0) { |
476 | strcat(fontPath, ":" ); |
477 | } |
478 | strcat(fontPath, fontdirs[i]); |
479 | } |
480 | } |
481 | free (fontdirs); |
482 | |
483 | return fontPath; |
484 | } |
485 | |
486 | /* |
487 | * The goal of this function is to find all "system" fonts which |
488 | * are needed by the JRE to display text in supported locales etc, and |
489 | * to support APIs which allow users to enumerate all system fonts and use |
490 | * them from their Java applications. |
491 | * The preferred mechanism is now using the new "fontconfig" library |
492 | * This exists on newer versions of Linux and Solaris (S10 and above) |
493 | * The library is dynamically located. The results are merged with |
494 | * a set of "known" locations and with the X11 font path, if running in |
495 | * a local X11 environment. |
496 | * The hardwired paths are built into the JDK binary so as new font locations |
497 | * are created on a host plaform for them to be located by the JRE they will |
498 | * need to be added ito the host's font configuration database, typically |
499 | * /etc/fonts/local.conf, and to ensure that directory contains a fonts.dir |
500 | * NB: Fontconfig also depends heavily for performance on the host O/S |
501 | * maintaining up to date caches. |
502 | * This is consistent with the requirements of the desktop environments |
503 | * on these OSes. |
504 | * This also frees us from X11 APIs as JRE is required to function in |
505 | * a "headless" mode where there is no Xserver. |
506 | */ |
507 | static char *getPlatformFontPathChars(JNIEnv *env, jboolean noType1, jboolean isX11) { |
508 | |
509 | char **fcdirs = NULL, **x11dirs = NULL, **knowndirs = NULL, *path = NULL; |
510 | |
511 | /* As of 1.5 we try to use fontconfig on both Solaris and Linux. |
512 | * If its not available NULL is returned. |
513 | */ |
514 | fcdirs = getFontConfigLocations(); |
515 | |
516 | #if defined(__linux__) |
517 | knowndirs = fullLinuxFontPath; |
518 | #elif defined(__solaris__) |
519 | knowndirs = fullSolarisFontPath; |
520 | #elif defined(_AIX) |
521 | knowndirs = fullAixFontPath; |
522 | #endif |
523 | /* REMIND: this code requires to be executed when the GraphicsEnvironment |
524 | * is already initialised. That is always true, but if it were not so, |
525 | * this code could throw an exception and the fontpath would fail to |
526 | * be initialised. |
527 | */ |
528 | #ifndef HEADLESS |
529 | if (isX11) { // The following only works in an x11 environment. |
530 | #if defined(__linux__) |
531 | /* There's no headless build on linux ... */ |
532 | if (!AWTIsHeadless()) { /* .. so need to call a function to check */ |
533 | #endif |
534 | /* Using the X11 font path to locate font files is now a fallback |
535 | * useful only if fontconfig failed, or is incomplete. So we could |
536 | * remove this code completely and the consequences should be rare |
537 | * and non-fatal. If this happens, then the calling Java code can |
538 | * be modified to no longer require that the AWT lock (the X11GE) |
539 | * be initialised prior to calling this code. |
540 | */ |
541 | AWT_LOCK(); |
542 | if (isDisplayLocal(env)) { |
543 | x11dirs = getX11FontPath(); |
544 | } |
545 | AWT_UNLOCK(); |
546 | #if defined(__linux__) |
547 | } |
548 | #endif |
549 | } |
550 | #endif /* !HEADLESS */ |
551 | path = mergePaths(fcdirs, x11dirs, knowndirs, noType1); |
552 | if (fcdirs != NULL) { |
553 | char **p = fcdirs; |
554 | while (*p != NULL) free(*p++); |
555 | free(fcdirs); |
556 | } |
557 | |
558 | if (x11dirs != NULL) { |
559 | char **p = x11dirs; |
560 | while (*p != NULL) free(*p++); |
561 | free(x11dirs); |
562 | } |
563 | |
564 | return path; |
565 | } |
566 | |
567 | JNIEXPORT jstring JNICALL Java_sun_awt_FcFontManager_getFontPathNative |
568 | (JNIEnv *env, jobject thiz, jboolean noType1, jboolean isX11) { |
569 | jstring ret; |
570 | static char *ptr = NULL; /* retain result across calls */ |
571 | |
572 | if (ptr == NULL) { |
573 | ptr = getPlatformFontPathChars(env, noType1, isX11); |
574 | } |
575 | ret = (*env)->NewStringUTF(env, ptr); |
576 | return ret; |
577 | } |
578 | |
579 | #include <dlfcn.h> |
580 | |
581 | #include <fontconfig/fontconfig.h> |
582 | |
583 | |
584 | static void* openFontConfig() { |
585 | |
586 | char *homeEnv; |
587 | static char *homeEnvStr = "HOME=" ; /* must be static */ |
588 | void* libfontconfig = NULL; |
589 | #ifdef __solaris__ |
590 | #define SYSINFOBUFSZ 8 |
591 | char sysinfobuf[SYSINFOBUFSZ]; |
592 | #endif |
593 | |
594 | /* Private workaround to not use fontconfig library. |
595 | * May be useful during testing/debugging |
596 | */ |
597 | char *useFC = getenv("USE_J2D_FONTCONFIG" ); |
598 | if (useFC != NULL && !strcmp(useFC, "no" )) { |
599 | return NULL; |
600 | } |
601 | |
602 | #ifdef __solaris__ |
603 | /* fontconfig is likely not properly configured on S8/S9 - skip it, |
604 | * although allow user to override this behaviour with an env. variable |
605 | * ie if USE_J2D_FONTCONFIG=yes then we skip this test. |
606 | * NB "4" is the length of a string which matches our patterns. |
607 | */ |
608 | if (useFC == NULL || strcmp(useFC, "yes" )) { |
609 | if (sysinfo(SI_RELEASE, sysinfobuf, SYSINFOBUFSZ) == 4) { |
610 | if ((!strcmp(sysinfobuf, "5.8" ) || !strcmp(sysinfobuf, "5.9" ))) { |
611 | return NULL; |
612 | } |
613 | } |
614 | } |
615 | #endif |
616 | |
617 | #if defined(_AIX) |
618 | /* On AIX, fontconfig is not a standard package supported by IBM. |
619 | * instead it has to be installed from the "AIX Toolbox for Linux Applications" |
620 | * site http://www-03.ibm.com/systems/power/software/aix/linux/toolbox/alpha.html |
621 | * and will be installed under /opt/freeware/lib/libfontconfig.a. |
622 | * Notice that the archive contains the real 32- and 64-bit shared libraries. |
623 | * We first try to load 'libfontconfig.so' from the default library path in the |
624 | * case the user has installed a private version of the library and if that |
625 | * doesn't succeed, we try the version from /opt/freeware/lib/libfontconfig.a |
626 | */ |
627 | libfontconfig = dlopen("libfontconfig.so" , RTLD_LOCAL|RTLD_LAZY); |
628 | if (libfontconfig == NULL) { |
629 | libfontconfig = dlopen("/opt/freeware/lib/libfontconfig.a(libfontconfig.so.1)" , RTLD_MEMBER|RTLD_LOCAL|RTLD_LAZY); |
630 | if (libfontconfig == NULL) { |
631 | return NULL; |
632 | } |
633 | } |
634 | #else |
635 | /* 64 bit sparc should pick up the right version from the lib path. |
636 | * New features may be added to libfontconfig, this is expected to |
637 | * be compatible with old features, but we may need to start |
638 | * distinguishing the library version, to know whether to expect |
639 | * certain symbols - and functionality - to be available. |
640 | * Also add explicit search for .so.1 in case .so symlink doesn't exist. |
641 | */ |
642 | libfontconfig = dlopen(FONTCONFIG_DLL_VERSIONED, RTLD_LOCAL|RTLD_LAZY); |
643 | if (libfontconfig == NULL) { |
644 | libfontconfig = dlopen(FONTCONFIG_DLL, RTLD_LOCAL|RTLD_LAZY); |
645 | if (libfontconfig == NULL) { |
646 | return NULL; |
647 | } |
648 | } |
649 | #endif |
650 | |
651 | /* Version 1.0 of libfontconfig crashes if HOME isn't defined in |
652 | * the environment. This should generally never happen, but we can't |
653 | * control it, and can't control the version of fontconfig, so iff |
654 | * its not defined we set it to an empty value which is sufficient |
655 | * to prevent a crash. I considered unsetting it before exit, but |
656 | * it doesn't appear to work on Solaris, so I will leave it set. |
657 | */ |
658 | homeEnv = getenv("HOME" ); |
659 | if (homeEnv == NULL) { |
660 | putenv(homeEnvStr); |
661 | } |
662 | |
663 | return libfontconfig; |
664 | } |
665 | |
666 | typedef void* (FcFiniFuncType)(); |
667 | |
668 | static void closeFontConfig(void* libfontconfig, jboolean fcFini) { |
669 | |
670 | /* NB FcFini is not in (eg) the Solaris 10 version of fontconfig. Its not |
671 | * clear if this means we are really leaking resources in those cases |
672 | * but it seems we should call this function when its available. |
673 | * But since the Swing GTK code may be still accessing the lib, its probably |
674 | * safest for now to just let this "leak" rather than potentially |
675 | * concurrently free global data still in use by other code. |
676 | */ |
677 | #if 0 |
678 | if (fcFini) { /* release resources */ |
679 | FcFiniFuncType FcFini = (FcFiniFuncType)dlsym(libfontconfig, "FcFini" ); |
680 | |
681 | if (FcFini != NULL) { |
682 | (*FcFini)(); |
683 | } |
684 | } |
685 | #endif |
686 | dlclose(libfontconfig); |
687 | } |
688 | |
689 | typedef FcConfig* (*FcInitLoadConfigFuncType)(); |
690 | typedef FcPattern* (*FcPatternBuildFuncType)(FcPattern *orig, ...); |
691 | typedef FcObjectSet* (*FcObjectSetFuncType)(const char *first, ...); |
692 | typedef FcFontSet* (*FcFontListFuncType)(FcConfig *config, |
693 | FcPattern *p, |
694 | FcObjectSet *os); |
695 | typedef FcResult (*FcPatternGetBoolFuncType)(const FcPattern *p, |
696 | const char *object, |
697 | int n, |
698 | FcBool *b); |
699 | typedef FcResult (*FcPatternGetIntegerFuncType)(const FcPattern *p, |
700 | const char *object, |
701 | int n, |
702 | int *i); |
703 | typedef FcResult (*FcPatternGetStringFuncType)(const FcPattern *p, |
704 | const char *object, |
705 | int n, |
706 | FcChar8 ** s); |
707 | typedef FcChar8* (*FcStrDirnameFuncType)(const FcChar8 *file); |
708 | typedef void (*FcPatternDestroyFuncType)(FcPattern *p); |
709 | typedef void (*FcFontSetDestroyFuncType)(FcFontSet *s); |
710 | typedef FcPattern* (*FcNameParseFuncType)(const FcChar8 *name); |
711 | typedef FcBool (*FcPatternAddStringFuncType)(FcPattern *p, |
712 | const char *object, |
713 | const FcChar8 *s); |
714 | typedef void (*FcDefaultSubstituteFuncType)(FcPattern *p); |
715 | typedef FcBool (*FcConfigSubstituteFuncType)(FcConfig *config, |
716 | FcPattern *p, |
717 | FcMatchKind kind); |
718 | typedef FcPattern* (*FcFontMatchFuncType)(FcConfig *config, |
719 | FcPattern *p, |
720 | FcResult *result); |
721 | typedef FcFontSet* (*FcFontSetCreateFuncType)(); |
722 | typedef FcBool (*FcFontSetAddFuncType)(FcFontSet *s, FcPattern *font); |
723 | |
724 | typedef FcResult (*FcPatternGetCharSetFuncType)(FcPattern *p, |
725 | const char *object, |
726 | int n, |
727 | FcCharSet **c); |
728 | typedef FcFontSet* (*FcFontSortFuncType)(FcConfig *config, |
729 | FcPattern *p, |
730 | FcBool trim, |
731 | FcCharSet **csp, |
732 | FcResult *result); |
733 | typedef FcCharSet* (*FcCharSetUnionFuncType)(const FcCharSet *a, |
734 | const FcCharSet *b); |
735 | typedef FcChar32 (*FcCharSetSubtractCountFuncType)(const FcCharSet *a, |
736 | const FcCharSet *b); |
737 | |
738 | typedef int (*FcGetVersionFuncType)(); |
739 | |
740 | typedef FcStrList* (*FcConfigGetCacheDirsFuncType)(FcConfig *config); |
741 | typedef FcChar8* (*FcStrListNextFuncType)(FcStrList *list); |
742 | typedef FcChar8* (*FcStrListDoneFuncType)(FcStrList *list); |
743 | |
744 | static char **getFontConfigLocations() { |
745 | |
746 | char **fontdirs; |
747 | int numdirs = 0; |
748 | FcInitLoadConfigFuncType FcInitLoadConfig; |
749 | FcPatternBuildFuncType FcPatternBuild; |
750 | FcObjectSetFuncType FcObjectSetBuild; |
751 | FcFontListFuncType FcFontList; |
752 | FcPatternGetStringFuncType FcPatternGetString; |
753 | FcStrDirnameFuncType FcStrDirname; |
754 | FcPatternDestroyFuncType FcPatternDestroy; |
755 | FcFontSetDestroyFuncType FcFontSetDestroy; |
756 | |
757 | FcConfig *fontconfig; |
758 | FcPattern *pattern; |
759 | FcObjectSet *objset; |
760 | FcFontSet *fontSet; |
761 | FcStrList *strList; |
762 | FcChar8 *str; |
763 | int i, f, found, len=0; |
764 | char **fontPath; |
765 | |
766 | void* libfontconfig = openFontConfig(); |
767 | |
768 | if (libfontconfig == NULL) { |
769 | return NULL; |
770 | } |
771 | |
772 | FcPatternBuild = |
773 | (FcPatternBuildFuncType)dlsym(libfontconfig, "FcPatternBuild" ); |
774 | FcObjectSetBuild = |
775 | (FcObjectSetFuncType)dlsym(libfontconfig, "FcObjectSetBuild" ); |
776 | FcFontList = |
777 | (FcFontListFuncType)dlsym(libfontconfig, "FcFontList" ); |
778 | FcPatternGetString = |
779 | (FcPatternGetStringFuncType)dlsym(libfontconfig, "FcPatternGetString" ); |
780 | FcStrDirname = |
781 | (FcStrDirnameFuncType)dlsym(libfontconfig, "FcStrDirname" ); |
782 | FcPatternDestroy = |
783 | (FcPatternDestroyFuncType)dlsym(libfontconfig, "FcPatternDestroy" ); |
784 | FcFontSetDestroy = |
785 | (FcFontSetDestroyFuncType)dlsym(libfontconfig, "FcFontSetDestroy" ); |
786 | |
787 | if (FcPatternBuild == NULL || |
788 | FcObjectSetBuild == NULL || |
789 | FcPatternGetString == NULL || |
790 | FcFontList == NULL || |
791 | FcStrDirname == NULL || |
792 | FcPatternDestroy == NULL || |
793 | FcFontSetDestroy == NULL) { /* problem with the library: return. */ |
794 | closeFontConfig(libfontconfig, JNI_FALSE); |
795 | return NULL; |
796 | } |
797 | |
798 | /* Make calls into the fontconfig library to build a search for |
799 | * outline fonts, and to get the set of full file paths from the matches. |
800 | * This set is returned from the call to FcFontList(..) |
801 | * We allocate an array of char* pointers sufficient to hold all |
802 | * the matches + 1 extra which ensures there will be a NULL after all |
803 | * valid entries. |
804 | * We call FcStrDirname strip the file name from the path, and |
805 | * check if we have yet seen this directory. If not we add a pointer to |
806 | * it into our array of char*. Note that FcStrDirname returns newly |
807 | * allocated storage so we can use this in the return char** value. |
808 | * Finally we clean up, freeing allocated resources, and return the |
809 | * array of unique directories. |
810 | */ |
811 | pattern = (*FcPatternBuild)(NULL, FC_OUTLINE, FcTypeBool, FcTrue, NULL); |
812 | objset = (*FcObjectSetBuild)(FC_FILE, NULL); |
813 | fontSet = (*FcFontList)(NULL, pattern, objset); |
814 | if (fontSet == NULL) { |
815 | /* FcFontList() may return NULL if fonts are not installed. */ |
816 | fontdirs = NULL; |
817 | } else { |
818 | fontdirs = (char**)calloc(fontSet->nfont+1, sizeof(char*)); |
819 | for (f=0; f < fontSet->nfont; f++) { |
820 | FcChar8 *file; |
821 | FcChar8 *dir; |
822 | if ((*FcPatternGetString)(fontSet->fonts[f], FC_FILE, 0, &file) == |
823 | FcResultMatch) { |
824 | dir = (*FcStrDirname)(file); |
825 | found = 0; |
826 | for (i=0;i<numdirs; i++) { |
827 | if (strcmp(fontdirs[i], (char*)dir) == 0) { |
828 | found = 1; |
829 | break; |
830 | } |
831 | } |
832 | if (!found) { |
833 | fontdirs[numdirs++] = (char*)dir; |
834 | } else { |
835 | free((char*)dir); |
836 | } |
837 | } |
838 | } |
839 | /* Free fontset if one was returned */ |
840 | (*FcFontSetDestroy)(fontSet); |
841 | } |
842 | |
843 | /* Free memory and close the ".so" */ |
844 | (*FcPatternDestroy)(pattern); |
845 | closeFontConfig(libfontconfig, JNI_TRUE); |
846 | return fontdirs; |
847 | } |
848 | |
849 | /* These are copied from sun.awt.SunHints. |
850 | * Consider initialising them as ints using JNI for more robustness. |
851 | */ |
852 | #define TEXT_AA_OFF 1 |
853 | #define TEXT_AA_ON 2 |
854 | #define TEXT_AA_LCD_HRGB 4 |
855 | #define TEXT_AA_LCD_HBGR 5 |
856 | #define TEXT_AA_LCD_VRGB 6 |
857 | #define TEXT_AA_LCD_VBGR 7 |
858 | |
859 | JNIEXPORT jint JNICALL |
860 | Java_sun_font_FontConfigManager_getFontConfigAASettings |
861 | (JNIEnv *env, jclass obj, jstring localeStr, jstring fcNameStr) { |
862 | |
863 | FcNameParseFuncType FcNameParse; |
864 | FcPatternAddStringFuncType FcPatternAddString; |
865 | FcConfigSubstituteFuncType FcConfigSubstitute; |
866 | FcDefaultSubstituteFuncType FcDefaultSubstitute; |
867 | FcFontMatchFuncType FcFontMatch; |
868 | FcPatternGetBoolFuncType FcPatternGetBool; |
869 | FcPatternGetIntegerFuncType FcPatternGetInteger; |
870 | FcPatternDestroyFuncType FcPatternDestroy; |
871 | |
872 | FcPattern *pattern, *matchPattern; |
873 | FcResult result; |
874 | FcBool antialias = FcFalse; |
875 | int rgba = 0; |
876 | const char *locale=NULL, *fcName=NULL; |
877 | void* libfontconfig; |
878 | |
879 | if (fcNameStr == NULL || localeStr == NULL) { |
880 | return -1; |
881 | } |
882 | |
883 | fcName = (*env)->GetStringUTFChars(env, fcNameStr, 0); |
884 | if (fcName == NULL) { |
885 | return -1; |
886 | } |
887 | locale = (*env)->GetStringUTFChars(env, localeStr, 0); |
888 | |
889 | if ((libfontconfig = openFontConfig()) == NULL) { |
890 | (*env)->ReleaseStringUTFChars (env, fcNameStr, (const char*)fcName); |
891 | if (locale) { |
892 | (*env)->ReleaseStringUTFChars (env, localeStr,(const char*)locale); |
893 | } |
894 | return -1; |
895 | } |
896 | |
897 | FcNameParse = (FcNameParseFuncType)dlsym(libfontconfig, "FcNameParse" ); |
898 | FcPatternAddString = |
899 | (FcPatternAddStringFuncType)dlsym(libfontconfig, "FcPatternAddString" ); |
900 | FcConfigSubstitute = |
901 | (FcConfigSubstituteFuncType)dlsym(libfontconfig, "FcConfigSubstitute" ); |
902 | FcDefaultSubstitute = (FcDefaultSubstituteFuncType) |
903 | dlsym(libfontconfig, "FcDefaultSubstitute" ); |
904 | FcFontMatch = (FcFontMatchFuncType)dlsym(libfontconfig, "FcFontMatch" ); |
905 | FcPatternGetBool = (FcPatternGetBoolFuncType) |
906 | dlsym(libfontconfig, "FcPatternGetBool" ); |
907 | FcPatternGetInteger = (FcPatternGetIntegerFuncType) |
908 | dlsym(libfontconfig, "FcPatternGetInteger" ); |
909 | FcPatternDestroy = |
910 | (FcPatternDestroyFuncType)dlsym(libfontconfig, "FcPatternDestroy" ); |
911 | |
912 | if (FcNameParse == NULL || |
913 | FcPatternAddString == NULL || |
914 | FcConfigSubstitute == NULL || |
915 | FcDefaultSubstitute == NULL || |
916 | FcFontMatch == NULL || |
917 | FcPatternGetBool == NULL || |
918 | FcPatternGetInteger == NULL || |
919 | FcPatternDestroy == NULL) { /* problem with the library: return. */ |
920 | |
921 | (*env)->ReleaseStringUTFChars (env, fcNameStr, (const char*)fcName); |
922 | if (locale) { |
923 | (*env)->ReleaseStringUTFChars (env, localeStr,(const char*)locale); |
924 | } |
925 | closeFontConfig(libfontconfig, JNI_FALSE); |
926 | return -1; |
927 | } |
928 | |
929 | |
930 | pattern = (*FcNameParse)((FcChar8 *)fcName); |
931 | if (locale != NULL) { |
932 | (*FcPatternAddString)(pattern, FC_LANG, (unsigned char*)locale); |
933 | } |
934 | (*FcConfigSubstitute)(NULL, pattern, FcMatchPattern); |
935 | (*FcDefaultSubstitute)(pattern); |
936 | matchPattern = (*FcFontMatch)(NULL, pattern, &result); |
937 | /* Perhaps should call FcFontRenderPrepare() here as some pattern |
938 | * elements might change as a result of that call, but I'm not seeing |
939 | * any difference in testing. |
940 | */ |
941 | if (matchPattern) { |
942 | (*FcPatternGetBool)(matchPattern, FC_ANTIALIAS, 0, &antialias); |
943 | (*FcPatternGetInteger)(matchPattern, FC_RGBA, 0, &rgba); |
944 | (*FcPatternDestroy)(matchPattern); |
945 | } |
946 | (*FcPatternDestroy)(pattern); |
947 | |
948 | (*env)->ReleaseStringUTFChars (env, fcNameStr, (const char*)fcName); |
949 | if (locale) { |
950 | (*env)->ReleaseStringUTFChars (env, localeStr, (const char*)locale); |
951 | } |
952 | closeFontConfig(libfontconfig, JNI_TRUE); |
953 | |
954 | if (antialias == FcFalse) { |
955 | return TEXT_AA_OFF; |
956 | } else if (rgba <= FC_RGBA_UNKNOWN || rgba >= FC_RGBA_NONE) { |
957 | return TEXT_AA_ON; |
958 | } else { |
959 | switch (rgba) { |
960 | case FC_RGBA_RGB : return TEXT_AA_LCD_HRGB; |
961 | case FC_RGBA_BGR : return TEXT_AA_LCD_HBGR; |
962 | case FC_RGBA_VRGB : return TEXT_AA_LCD_VRGB; |
963 | case FC_RGBA_VBGR : return TEXT_AA_LCD_VBGR; |
964 | default : return TEXT_AA_LCD_HRGB; // should not get here. |
965 | } |
966 | } |
967 | } |
968 | |
969 | JNIEXPORT jint JNICALL |
970 | Java_sun_font_FontConfigManager_getFontConfigVersion |
971 | (JNIEnv *env, jclass obj) { |
972 | |
973 | void* libfontconfig; |
974 | FcGetVersionFuncType FcGetVersion; |
975 | int version = 0; |
976 | |
977 | if ((libfontconfig = openFontConfig()) == NULL) { |
978 | return 0; |
979 | } |
980 | |
981 | FcGetVersion = (FcGetVersionFuncType)dlsym(libfontconfig, "FcGetVersion" ); |
982 | |
983 | if (FcGetVersion == NULL) { |
984 | closeFontConfig(libfontconfig, JNI_FALSE); |
985 | return 0; |
986 | } |
987 | version = (*FcGetVersion)(); |
988 | closeFontConfig(libfontconfig, JNI_FALSE); |
989 | |
990 | return version; |
991 | } |
992 | |
993 | |
994 | JNIEXPORT void JNICALL |
995 | Java_sun_font_FontConfigManager_getFontConfig |
996 | (JNIEnv *env, jclass obj, jstring localeStr, jobject fcInfoObj, |
997 | jobjectArray fcCompFontArray, jboolean includeFallbacks) { |
998 | |
999 | FcNameParseFuncType FcNameParse; |
1000 | FcPatternAddStringFuncType FcPatternAddString; |
1001 | FcConfigSubstituteFuncType FcConfigSubstitute; |
1002 | FcDefaultSubstituteFuncType FcDefaultSubstitute; |
1003 | FcFontMatchFuncType FcFontMatch; |
1004 | FcPatternGetStringFuncType FcPatternGetString; |
1005 | FcPatternDestroyFuncType FcPatternDestroy; |
1006 | FcPatternGetCharSetFuncType FcPatternGetCharSet; |
1007 | FcFontSortFuncType FcFontSort; |
1008 | FcFontSetDestroyFuncType FcFontSetDestroy; |
1009 | FcCharSetUnionFuncType FcCharSetUnion; |
1010 | FcCharSetSubtractCountFuncType FcCharSetSubtractCount; |
1011 | FcGetVersionFuncType FcGetVersion; |
1012 | FcConfigGetCacheDirsFuncType FcConfigGetCacheDirs; |
1013 | FcStrListNextFuncType FcStrListNext; |
1014 | FcStrListDoneFuncType FcStrListDone; |
1015 | |
1016 | int i, arrlen; |
1017 | jobject fcCompFontObj; |
1018 | jstring fcNameStr, jstr; |
1019 | const char *locale, *fcName; |
1020 | FcPattern *pattern; |
1021 | FcResult result; |
1022 | void* libfontconfig; |
1023 | jfieldID fcNameID, fcFirstFontID, fcAllFontsID, fcVersionID, fcCacheDirsID; |
1024 | jfieldID familyNameID, styleNameID, fullNameID, fontFileID; |
1025 | jmethodID fcFontCons; |
1026 | char* debugMinGlyphsStr = getenv("J2D_DEBUG_MIN_GLYPHS" ); |
1027 | jclass fcInfoClass; |
1028 | jclass fcCompFontClass; |
1029 | jclass fcFontClass; |
1030 | |
1031 | CHECK_NULL(fcInfoObj); |
1032 | CHECK_NULL(fcCompFontArray); |
1033 | |
1034 | fcInfoClass = |
1035 | (*env)->FindClass(env, "sun/font/FontConfigManager$FontConfigInfo" ); |
1036 | CHECK_NULL(fcInfoClass); |
1037 | fcCompFontClass = |
1038 | (*env)->FindClass(env, "sun/font/FontConfigManager$FcCompFont" ); |
1039 | CHECK_NULL(fcCompFontClass); |
1040 | fcFontClass = |
1041 | (*env)->FindClass(env, "sun/font/FontConfigManager$FontConfigFont" ); |
1042 | CHECK_NULL(fcFontClass); |
1043 | |
1044 | |
1045 | CHECK_NULL(fcVersionID = (*env)->GetFieldID(env, fcInfoClass, "fcVersion" , "I" )); |
1046 | CHECK_NULL(fcCacheDirsID = (*env)->GetFieldID(env, fcInfoClass, "cacheDirs" , |
1047 | "[Ljava/lang/String;" )); |
1048 | CHECK_NULL(fcNameID = (*env)->GetFieldID(env, fcCompFontClass, |
1049 | "fcName" , "Ljava/lang/String;" )); |
1050 | CHECK_NULL(fcFirstFontID = (*env)->GetFieldID(env, fcCompFontClass, "firstFont" , |
1051 | "Lsun/font/FontConfigManager$FontConfigFont;" )); |
1052 | CHECK_NULL(fcAllFontsID = (*env)->GetFieldID(env, fcCompFontClass, "allFonts" , |
1053 | "[Lsun/font/FontConfigManager$FontConfigFont;" )); |
1054 | CHECK_NULL(fcFontCons = (*env)->GetMethodID(env, fcFontClass, "<init>" , "()V" )); |
1055 | CHECK_NULL(familyNameID = (*env)->GetFieldID(env, fcFontClass, |
1056 | "familyName" , "Ljava/lang/String;" )); |
1057 | CHECK_NULL(styleNameID = (*env)->GetFieldID(env, fcFontClass, |
1058 | "styleStr" , "Ljava/lang/String;" )); |
1059 | CHECK_NULL(fullNameID = (*env)->GetFieldID(env, fcFontClass, |
1060 | "fullName" , "Ljava/lang/String;" )); |
1061 | CHECK_NULL(fontFileID = (*env)->GetFieldID(env, fcFontClass, |
1062 | "fontFile" , "Ljava/lang/String;" )); |
1063 | |
1064 | if ((libfontconfig = openFontConfig()) == NULL) { |
1065 | return; |
1066 | } |
1067 | |
1068 | FcNameParse = (FcNameParseFuncType)dlsym(libfontconfig, "FcNameParse" ); |
1069 | FcPatternAddString = |
1070 | (FcPatternAddStringFuncType)dlsym(libfontconfig, "FcPatternAddString" ); |
1071 | FcConfigSubstitute = |
1072 | (FcConfigSubstituteFuncType)dlsym(libfontconfig, "FcConfigSubstitute" ); |
1073 | FcDefaultSubstitute = (FcDefaultSubstituteFuncType) |
1074 | dlsym(libfontconfig, "FcDefaultSubstitute" ); |
1075 | FcFontMatch = (FcFontMatchFuncType)dlsym(libfontconfig, "FcFontMatch" ); |
1076 | FcPatternGetString = |
1077 | (FcPatternGetStringFuncType)dlsym(libfontconfig, "FcPatternGetString" ); |
1078 | FcPatternDestroy = |
1079 | (FcPatternDestroyFuncType)dlsym(libfontconfig, "FcPatternDestroy" ); |
1080 | FcPatternGetCharSet = |
1081 | (FcPatternGetCharSetFuncType)dlsym(libfontconfig, |
1082 | "FcPatternGetCharSet" ); |
1083 | FcFontSort = |
1084 | (FcFontSortFuncType)dlsym(libfontconfig, "FcFontSort" ); |
1085 | FcFontSetDestroy = |
1086 | (FcFontSetDestroyFuncType)dlsym(libfontconfig, "FcFontSetDestroy" ); |
1087 | FcCharSetUnion = |
1088 | (FcCharSetUnionFuncType)dlsym(libfontconfig, "FcCharSetUnion" ); |
1089 | FcCharSetSubtractCount = |
1090 | (FcCharSetSubtractCountFuncType)dlsym(libfontconfig, |
1091 | "FcCharSetSubtractCount" ); |
1092 | FcGetVersion = (FcGetVersionFuncType)dlsym(libfontconfig, "FcGetVersion" ); |
1093 | |
1094 | if (FcNameParse == NULL || |
1095 | FcPatternAddString == NULL || |
1096 | FcConfigSubstitute == NULL || |
1097 | FcDefaultSubstitute == NULL || |
1098 | FcFontMatch == NULL || |
1099 | FcPatternGetString == NULL || |
1100 | FcPatternDestroy == NULL || |
1101 | FcPatternGetCharSet == NULL || |
1102 | FcFontSetDestroy == NULL || |
1103 | FcCharSetUnion == NULL || |
1104 | FcGetVersion == NULL || |
1105 | FcCharSetSubtractCount == NULL) {/* problem with the library: return.*/ |
1106 | closeFontConfig(libfontconfig, JNI_FALSE); |
1107 | return; |
1108 | } |
1109 | |
1110 | (*env)->SetIntField(env, fcInfoObj, fcVersionID, (*FcGetVersion)()); |
1111 | |
1112 | /* Optionally get the cache dir locations. This isn't |
1113 | * available until v 2.4.x, but this is OK since on those later versions |
1114 | * we can check the time stamps on the cache dirs to see if we |
1115 | * are out of date. There are a couple of assumptions here. First |
1116 | * that the time stamp on the directory changes when the contents are |
1117 | * updated. Secondly that the locations don't change. The latter is |
1118 | * most likely if a new version of fontconfig is installed, but we also |
1119 | * invalidate the cache if we detect that. Arguably even that is "rare", |
1120 | * and most likely is tied to an OS upgrade which gets a new file anyway. |
1121 | */ |
1122 | FcConfigGetCacheDirs = |
1123 | (FcConfigGetCacheDirsFuncType)dlsym(libfontconfig, |
1124 | "FcConfigGetCacheDirs" ); |
1125 | FcStrListNext = |
1126 | (FcStrListNextFuncType)dlsym(libfontconfig, "FcStrListNext" ); |
1127 | FcStrListDone = |
1128 | (FcStrListDoneFuncType)dlsym(libfontconfig, "FcStrListDone" ); |
1129 | if (FcStrListNext != NULL && FcStrListDone != NULL && |
1130 | FcConfigGetCacheDirs != NULL) { |
1131 | |
1132 | FcStrList* cacheDirs; |
1133 | FcChar8* cacheDir; |
1134 | int cnt = 0; |
1135 | jobject cacheDirArray = |
1136 | (*env)->GetObjectField(env, fcInfoObj, fcCacheDirsID); |
1137 | int max = (*env)->GetArrayLength(env, cacheDirArray); |
1138 | |
1139 | cacheDirs = (*FcConfigGetCacheDirs)(NULL); |
1140 | if (cacheDirs != NULL) { |
1141 | while ((cnt < max) && (cacheDir = (*FcStrListNext)(cacheDirs))) { |
1142 | jstr = (*env)->NewStringUTF(env, (const char*)cacheDir); |
1143 | JNU_CHECK_EXCEPTION(env); |
1144 | |
1145 | (*env)->SetObjectArrayElement(env, cacheDirArray, cnt++, jstr); |
1146 | (*env)->DeleteLocalRef(env, jstr); |
1147 | } |
1148 | (*FcStrListDone)(cacheDirs); |
1149 | } |
1150 | } |
1151 | |
1152 | locale = (*env)->GetStringUTFChars(env, localeStr, 0); |
1153 | if (locale == NULL) { |
1154 | (*env)->ExceptionClear(env); |
1155 | JNU_ThrowOutOfMemoryError(env, "Could not create locale" ); |
1156 | return; |
1157 | } |
1158 | |
1159 | arrlen = (*env)->GetArrayLength(env, fcCompFontArray); |
1160 | for (i=0; i<arrlen; i++) { |
1161 | FcFontSet* fontset; |
1162 | int fn, j, fontCount, nfonts; |
1163 | unsigned int minGlyphs; |
1164 | FcChar8 **family, **styleStr, **fullname, **file; |
1165 | jarray fcFontArr = NULL; |
1166 | FcCharSet *unionCharset = NULL; |
1167 | |
1168 | fcCompFontObj = (*env)->GetObjectArrayElement(env, fcCompFontArray, i); |
1169 | fcNameStr = |
1170 | (jstring)((*env)->GetObjectField(env, fcCompFontObj, fcNameID)); |
1171 | fcName = (*env)->GetStringUTFChars(env, fcNameStr, 0); |
1172 | if (fcName == NULL) { |
1173 | (*env)->DeleteLocalRef(env, fcCompFontObj); |
1174 | (*env)->DeleteLocalRef(env, fcNameStr); |
1175 | continue; |
1176 | } |
1177 | pattern = (*FcNameParse)((FcChar8 *)fcName); |
1178 | (*env)->ReleaseStringUTFChars(env, fcNameStr, (const char*)fcName); |
1179 | (*env)->DeleteLocalRef(env, fcNameStr); |
1180 | if (pattern == NULL) { |
1181 | closeFontConfig(libfontconfig, JNI_FALSE); |
1182 | return; |
1183 | } |
1184 | |
1185 | /* locale may not usually be necessary as fontconfig appears to apply |
1186 | * this anyway based on the user's environment. However we want |
1187 | * to use the value of the JDK startup locale so this should take |
1188 | * care of it. |
1189 | */ |
1190 | if (locale != NULL) { |
1191 | (*FcPatternAddString)(pattern, FC_LANG, (unsigned char*)locale); |
1192 | } |
1193 | (*FcConfigSubstitute)(NULL, pattern, FcMatchPattern); |
1194 | (*FcDefaultSubstitute)(pattern); |
1195 | fontset = (*FcFontSort)(NULL, pattern, FcTrue, NULL, &result); |
1196 | if (fontset == NULL) { |
1197 | (*FcPatternDestroy)(pattern); |
1198 | closeFontConfig(libfontconfig, JNI_FALSE); |
1199 | return; |
1200 | } |
1201 | |
1202 | /* fontconfig returned us "nfonts". If we are just getting the |
1203 | * first font, we set nfont to zero. Otherwise we use "nfonts". |
1204 | * Next create separate C arrrays of length nfonts for family file etc. |
1205 | * Inspect the returned fonts and the ones we like (adds enough glyphs) |
1206 | * are added to the arrays and we increment 'fontCount'. |
1207 | */ |
1208 | nfonts = fontset->nfont; |
1209 | family = (FcChar8**)calloc(nfonts, sizeof(FcChar8*)); |
1210 | styleStr = (FcChar8**)calloc(nfonts, sizeof(FcChar8*)); |
1211 | fullname = (FcChar8**)calloc(nfonts, sizeof(FcChar8*)); |
1212 | file = (FcChar8**)calloc(nfonts, sizeof(FcChar8*)); |
1213 | if (family == NULL || styleStr == NULL || |
1214 | fullname == NULL || file == NULL) { |
1215 | if (family != NULL) { |
1216 | free(family); |
1217 | } |
1218 | if (styleStr != NULL) { |
1219 | free(styleStr); |
1220 | } |
1221 | if (fullname != NULL) { |
1222 | free(fullname); |
1223 | } |
1224 | if (file != NULL) { |
1225 | free(file); |
1226 | } |
1227 | (*FcPatternDestroy)(pattern); |
1228 | (*FcFontSetDestroy)(fontset); |
1229 | closeFontConfig(libfontconfig, JNI_FALSE); |
1230 | return; |
1231 | } |
1232 | fontCount = 0; |
1233 | minGlyphs = 20; |
1234 | if (debugMinGlyphsStr != NULL) { |
1235 | int val = minGlyphs; |
1236 | sscanf(debugMinGlyphsStr, "%5d" , &val); |
1237 | if (val >= 0 && val <= 65536) { |
1238 | minGlyphs = val; |
1239 | } |
1240 | } |
1241 | |
1242 | for (j=0; j<nfonts; j++) { |
1243 | FcPattern *fontPattern = fontset->fonts[j]; |
1244 | FcChar8 *fontformat; |
1245 | FcCharSet *charset = NULL; |
1246 | |
1247 | fontformat = NULL; |
1248 | (*FcPatternGetString)(fontPattern, FC_FONTFORMAT, 0, &fontformat); |
1249 | /* We only want TrueType fonts but some Linuxes still depend |
1250 | * on Type 1 fonts for some Locale support, so we'll allow |
1251 | * them there. |
1252 | */ |
1253 | if (fontformat != NULL |
1254 | && (strcmp((char*)fontformat, "TrueType" ) != 0) |
1255 | #if defined(__linux__) || defined(_AIX) |
1256 | && (strcmp((char*)fontformat, "Type 1" ) != 0) |
1257 | && (strcmp((char*)fontformat, "CFF" ) != 0) |
1258 | #endif |
1259 | ) { |
1260 | continue; |
1261 | } |
1262 | result = (*FcPatternGetCharSet)(fontPattern, |
1263 | FC_CHARSET, 0, &charset); |
1264 | if (result != FcResultMatch) { |
1265 | free(family); |
1266 | free(fullname); |
1267 | free(styleStr); |
1268 | free(file); |
1269 | (*FcPatternDestroy)(pattern); |
1270 | (*FcFontSetDestroy)(fontset); |
1271 | closeFontConfig(libfontconfig, JNI_FALSE); |
1272 | return; |
1273 | } |
1274 | |
1275 | /* We don't want 20 or 30 fonts, so once we hit 10 fonts, |
1276 | * then require that they really be adding value. Too many |
1277 | * adversely affects load time for minimal value-add. |
1278 | * This is still likely far more than we've had in the past. |
1279 | */ |
1280 | if (j==10) { |
1281 | minGlyphs = 50; |
1282 | } |
1283 | if (unionCharset == NULL) { |
1284 | unionCharset = charset; |
1285 | } else { |
1286 | if ((*FcCharSetSubtractCount)(charset, unionCharset) |
1287 | > minGlyphs) { |
1288 | unionCharset = (* FcCharSetUnion)(unionCharset, charset); |
1289 | } else { |
1290 | continue; |
1291 | } |
1292 | } |
1293 | |
1294 | fontCount++; // found a font we will use. |
1295 | (*FcPatternGetString)(fontPattern, FC_FILE, 0, &file[j]); |
1296 | (*FcPatternGetString)(fontPattern, FC_FAMILY, 0, &family[j]); |
1297 | (*FcPatternGetString)(fontPattern, FC_STYLE, 0, &styleStr[j]); |
1298 | (*FcPatternGetString)(fontPattern, FC_FULLNAME, 0, &fullname[j]); |
1299 | if (!includeFallbacks) { |
1300 | break; |
1301 | } |
1302 | if (fontCount == 254) { |
1303 | break; // CompositeFont will only use up to 254 slots from here. |
1304 | } |
1305 | } |
1306 | |
1307 | /* Once we get here 'fontCount' is the number of returned fonts |
1308 | * we actually want to use, so we create 'fcFontArr' of that length. |
1309 | * The non-null entries of "family[]" etc are those fonts. |
1310 | * Then loop again over all nfonts adding just those non-null ones |
1311 | * to 'fcFontArr'. If its null (we didn't want the font) |
1312 | * then we don't enter the main body. |
1313 | * So we should never get more than 'fontCount' entries. |
1314 | */ |
1315 | if (includeFallbacks) { |
1316 | fcFontArr = |
1317 | (*env)->NewObjectArray(env, fontCount, fcFontClass, NULL); |
1318 | if (IS_NULL(fcFontArr)) { |
1319 | free(family); |
1320 | free(fullname); |
1321 | free(styleStr); |
1322 | free(file); |
1323 | (*FcPatternDestroy)(pattern); |
1324 | (*FcFontSetDestroy)(fontset); |
1325 | closeFontConfig(libfontconfig, JNI_FALSE); |
1326 | return; |
1327 | } |
1328 | (*env)->SetObjectField(env,fcCompFontObj, fcAllFontsID, fcFontArr); |
1329 | } |
1330 | fn=0; |
1331 | |
1332 | for (j=0;j<nfonts;j++) { |
1333 | if (family[j] != NULL) { |
1334 | jobject fcFont = |
1335 | (*env)->NewObject(env, fcFontClass, fcFontCons); |
1336 | if (IS_NULL(fcFont)) break; |
1337 | jstr = (*env)->NewStringUTF(env, (const char*)family[j]); |
1338 | if (IS_NULL(jstr)) break; |
1339 | (*env)->SetObjectField(env, fcFont, familyNameID, jstr); |
1340 | (*env)->DeleteLocalRef(env, jstr); |
1341 | if (file[j] != NULL) { |
1342 | jstr = (*env)->NewStringUTF(env, (const char*)file[j]); |
1343 | if (IS_NULL(jstr)) break; |
1344 | (*env)->SetObjectField(env, fcFont, fontFileID, jstr); |
1345 | (*env)->DeleteLocalRef(env, jstr); |
1346 | } |
1347 | if (styleStr[j] != NULL) { |
1348 | jstr = (*env)->NewStringUTF(env, (const char*)styleStr[j]); |
1349 | if (IS_NULL(jstr)) break; |
1350 | (*env)->SetObjectField(env, fcFont, styleNameID, jstr); |
1351 | (*env)->DeleteLocalRef(env, jstr); |
1352 | } |
1353 | if (fullname[j] != NULL) { |
1354 | jstr = (*env)->NewStringUTF(env, (const char*)fullname[j]); |
1355 | if (IS_NULL(jstr)) break; |
1356 | (*env)->SetObjectField(env, fcFont, fullNameID, jstr); |
1357 | (*env)->DeleteLocalRef(env, jstr); |
1358 | } |
1359 | if (fn==0) { |
1360 | (*env)->SetObjectField(env, fcCompFontObj, |
1361 | fcFirstFontID, fcFont); |
1362 | } |
1363 | if (includeFallbacks) { |
1364 | (*env)->SetObjectArrayElement(env, fcFontArr, fn++,fcFont); |
1365 | } else { |
1366 | (*env)->DeleteLocalRef(env, fcFont); |
1367 | break; |
1368 | } |
1369 | (*env)->DeleteLocalRef(env, fcFont); |
1370 | } |
1371 | } |
1372 | if (includeFallbacks) { |
1373 | (*env)->DeleteLocalRef(env, fcFontArr); |
1374 | } |
1375 | (*env)->DeleteLocalRef(env, fcCompFontObj); |
1376 | (*FcFontSetDestroy)(fontset); |
1377 | (*FcPatternDestroy)(pattern); |
1378 | free(family); |
1379 | free(styleStr); |
1380 | free(fullname); |
1381 | free(file); |
1382 | } |
1383 | |
1384 | /* release resources and close the ".so" */ |
1385 | |
1386 | if (locale) { |
1387 | (*env)->ReleaseStringUTFChars (env, localeStr, (const char*)locale); |
1388 | } |
1389 | closeFontConfig(libfontconfig, JNI_TRUE); |
1390 | } |
1391 | |