blob: d863d265b580cc22db334915c8c7b2c510906910 [file] [log] [blame]
J. Duke319a3b92007-12-01 00:00:00 +00001/*
2 * Copyright 1998-2006 Sun Microsystems, Inc. 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. Sun designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
22 * CA 95054 USA or visit www.sun.com if you need additional information or
23 * have any questions.
24 */
25
26#ifdef __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 <sun_font_FontManager.h>
44#ifndef HEADLESS
45#include <X11/Xlib.h>
46#include <awt.h>
47#else
48/* locks ought to be included from awt.h */
49#define AWT_LOCK()
50#define AWT_UNLOCK()
51#endif /* !HEADLESS */
52
53#if defined(__linux__) && !defined(MAP_FAILED)
54#define MAP_FAILED ((caddr_t)-1)
55#endif
56
57#ifndef HEADLESS
58extern Display *awt_display;
59#endif /* !HEADLESS */
60
61
62#define MAXFDIRS 512 /* Max number of directories that contain fonts */
63
64#ifndef __linux__
65/*
66 * This can be set in the makefile to "/usr/X11" if so desired.
67 */
68#ifndef OPENWINHOMELIB
69#define OPENWINHOMELIB "/usr/openwin/lib/"
70#endif
71
72/* This is all known Solaris X11 directories on Solaris 8, 9 and 10.
73 * It is ordered to give precedence to TrueType directories.
74 * It is needed if fontconfig is not installed or configured properly.
75 */
76static char *fullSolarisFontPath[] = {
77 OPENWINHOMELIB "X11/fonts/TrueType",
78 OPENWINHOMELIB "locale/euro_fonts/X11/fonts/TrueType",
79 OPENWINHOMELIB "locale/iso_8859_2/X11/fonts/TrueType",
80 OPENWINHOMELIB "locale/iso_8859_5/X11/fonts/TrueType",
81 OPENWINHOMELIB "locale/iso_8859_7/X11/fonts/TrueType",
82 OPENWINHOMELIB "locale/iso_8859_8/X11/fonts/TrueType",
83 OPENWINHOMELIB "locale/iso_8859_9/X11/fonts/TrueType",
84 OPENWINHOMELIB "locale/iso_8859_13/X11/fonts/TrueType",
85 OPENWINHOMELIB "locale/iso_8859_15/X11/fonts/TrueType",
86 OPENWINHOMELIB "locale/ar/X11/fonts/TrueType",
87 OPENWINHOMELIB "locale/hi_IN.UTF-8/X11/fonts/TrueType",
88 OPENWINHOMELIB "locale/ja/X11/fonts/TT",
89 OPENWINHOMELIB "locale/ko/X11/fonts/TrueType",
90 OPENWINHOMELIB "locale/ko.UTF-8/X11/fonts/TrueType",
91 OPENWINHOMELIB "locale/KOI8-R/X11/fonts/TrueType",
92 OPENWINHOMELIB "locale/ru.ansi-1251/X11/fonts/TrueType",
93 OPENWINHOMELIB "locale/th_TH/X11/fonts/TrueType",
94 OPENWINHOMELIB "locale/zh_TW/X11/fonts/TrueType",
95 OPENWINHOMELIB "locale/zh_TW.BIG5/X11/fonts/TT",
96 OPENWINHOMELIB "locale/zh_HK.BIG5HK/X11/fonts/TT",
97 OPENWINHOMELIB "locale/zh_CN.GB18030/X11/fonts/TrueType",
98 OPENWINHOMELIB "locale/zh/X11/fonts/TrueType",
99 OPENWINHOMELIB "locale/zh.GBK/X11/fonts/TrueType",
100 OPENWINHOMELIB "X11/fonts/Type1",
101 OPENWINHOMELIB "X11/fonts/Type1/sun",
102 OPENWINHOMELIB "X11/fonts/Type1/sun/outline",
103 OPENWINHOMELIB "locale/iso_8859_2/X11/fonts/Type1",
104 OPENWINHOMELIB "locale/iso_8859_4/X11/fonts/Type1",
105 OPENWINHOMELIB "locale/iso_8859_5/X11/fonts/Type1",
106 OPENWINHOMELIB "locale/iso_8859_7/X11/fonts/Type1",
107 OPENWINHOMELIB "locale/iso_8859_8/X11/fonts/Type1",
108 OPENWINHOMELIB "locale/iso_8859_9/X11/fonts/Type1",
109 OPENWINHOMELIB "locale/iso_8859_13/X11/fonts/Type1",
110 OPENWINHOMELIB "locale/ar/X11/fonts/Type1",
111 NULL, /* terminates the list */
112};
113
114#else /* __linux */
115/* All the known interesting locations we have discovered on
116 * various flavors of Linux
117 */
118static char *fullLinuxFontPath[] = {
119 "/usr/X11R6/lib/X11/fonts/TrueType", /* RH 7.1+ */
120 "/usr/X11R6/lib/X11/fonts/truetype", /* SuSE */
121 "/usr/X11R6/lib/X11/fonts/tt",
122 "/usr/X11R6/lib/X11/fonts/TTF",
123 "/usr/X11R6/lib/X11/fonts/OTF", /* RH 9.0 (but empty!) */
124 "/usr/share/fonts/ja/TrueType", /* RH 7.2+ */
125 "/usr/share/fonts/truetype",
126 "/usr/share/fonts/ko/TrueType", /* RH 9.0 */
127 "/usr/share/fonts/zh_CN/TrueType", /* RH 9.0 */
128 "/usr/share/fonts/zh_TW/TrueType", /* RH 9.0 */
129 "/var/lib/defoma/x-ttcidfont-conf.d/dirs/TrueType", /* Debian */
130 "/usr/X11R6/lib/X11/fonts/Type1",
131 "/usr/share/fonts/default/Type1", /* RH 9.0 */
132 NULL, /* terminates the list */
133};
134#endif
135
136static char **getFontConfigLocations();
137
138typedef struct {
139 const char *name[MAXFDIRS];
140 int num;
141} fDirRecord, *fDirRecordPtr;
142
143#ifndef HEADLESS
144
145/*
146 * Returns True if display is local, False of it's remote.
147 */
148jboolean isDisplayLocal(JNIEnv *env) {
149 static jboolean isLocal = False;
150 static jboolean isLocalSet = False;
151 jboolean ret;
152
153 if (isLocalSet) {
154 return isLocal;
155 }
156
157 isLocal = JNU_CallStaticMethodByName(env, NULL,
158 "sun/awt/X11GraphicsEnvironment",
159 "isDisplayLocal",
160 "()Z").z;
161 isLocalSet = True;
162 return isLocal;
163}
164
165static void AddFontsToX11FontPath ( fDirRecord *fDirP )
166{
167 char *onePath;
168 int index, nPaths;
169 int origNumPaths, length;
170 int origIndex;
171 int totalDirCount;
172 char **origFontPath;
173 char **tempFontPath;
174 int doNotAppend;
175 int *appendDirList;
176 char **newFontPath;
177 int err, compareLength;
178 char fontDirPath[512];
179 int dirFile;
180
181 doNotAppend = 0;
182
183 if ( fDirP->num == 0 ) return;
184
185 appendDirList = malloc ( fDirP->num * sizeof ( int ));
186 if ( appendDirList == NULL ) {
187 return; /* if it fails we cannot do much */
188 }
189
190 origFontPath = XGetFontPath ( awt_display, &nPaths );
191
192 totalDirCount = nPaths;
193 origNumPaths = nPaths;
194 tempFontPath = origFontPath;
195
196
197 for (index = 0; index < fDirP->num; index++ ) {
198
199 doNotAppend = 0;
200
201 tempFontPath = origFontPath;
202 for ( origIndex = 0; origIndex < nPaths; origIndex++ ) {
203
204 onePath = *tempFontPath;
205
206 compareLength = strlen ( onePath );
207 if ( onePath[compareLength -1] == '/' )
208 compareLength--;
209
210 /* there is a slash at the end of every solaris X11 font path name */
211 if ( strncmp ( onePath, fDirP->name[index], compareLength ) == 0 ) {
212 doNotAppend = 1;
213 break;
214 }
215 tempFontPath++;
216 }
217
218 appendDirList[index] = 0;
219 if ( doNotAppend == 0 ) {
220 strcpy ( fontDirPath, fDirP->name[index] );
221 strcat ( fontDirPath, "/fonts.dir" );
222 dirFile = open ( fontDirPath, O_RDONLY, 0 );
223 if ( dirFile == -1 ) {
224 doNotAppend = 1;
225 } else {
226 close ( dirFile );
227 totalDirCount++;
228 appendDirList[index] = 1;
229 }
230 }
231
232 }
233
234 /* if no changes are required do not bother to do a setfontpath */
235 if ( totalDirCount == nPaths ) {
236 free ( ( void *) appendDirList );
237 XFreeFontPath ( origFontPath );
238 return;
239 }
240
241
242 newFontPath = malloc ( totalDirCount * sizeof ( char **) );
243 /* if it fails free things and get out */
244 if ( newFontPath == NULL ) {
245 free ( ( void *) appendDirList );
246 XFreeFontPath ( origFontPath );
247 return;
248 }
249
250 for ( origIndex = 0; origIndex < nPaths; origIndex++ ) {
251 onePath = origFontPath[origIndex];
252 newFontPath[origIndex] = onePath;
253 }
254
255 /* now add the other font paths */
256
257 for (index = 0; index < fDirP->num; index++ ) {
258
259 if ( appendDirList[index] == 1 ) {
260
261 /* printf ( "Appending %s\n", fDirP->name[index] ); */
262
263 onePath = malloc ( ( strlen (fDirP->name[index]) + 2 )* sizeof( char ) );
264 strcpy ( onePath, fDirP->name[index] );
265 strcat ( onePath, "/" );
266 newFontPath[nPaths++] = onePath;
267 /* printf ( "The path to be appended is %s\n", onePath ); */
268 }
269 }
270
271 /* printf ( "The dir count = %d\n", totalDirCount ); */
272 free ( ( void *) appendDirList );
273
274 XSetFontPath ( awt_display, newFontPath, totalDirCount );
275
276 for ( index = origNumPaths; index < totalDirCount; index++ ) {
277 free( newFontPath[index] );
278 }
279
280 free ( (void *) newFontPath );
281 XFreeFontPath ( origFontPath );
282 return;
283}
284#endif /* !HEADLESS */
285
286
287#ifndef HEADLESS
288static char **getX11FontPath ()
289{
290 char **x11Path, **fontdirs;
291 int i, pos, slen, nPaths, numDirs;
292
293 x11Path = XGetFontPath (awt_display, &nPaths);
294
295 /* This isn't ever going to be perfect: the font path may contain
296 * much we aren't interested in, but the cost should be moderate
297 * Exclude all directories that contain the strings "Speedo","/F3/",
298 * "75dpi", "100dpi", "misc" or "bitmap", or don't begin with a "/",
299 * the last of which should exclude font servers.
300 * Also exclude the user specific ".gnome*" directories which
301 * aren't going to contain the system fonts we need.
302 * Hopefully we are left only with Type1 and TrueType directories.
303 * It doesn't matter much if there are extraneous directories, it'll just
304 * cost us a little wasted effort upstream.
305 */
306 fontdirs = (char**)calloc(nPaths+1, sizeof(char*));
307 pos = 0;
308 for (i=0; i < nPaths; i++) {
309 if (x11Path[i][0] != '/') {
310 continue;
311 }
312 if (strstr(x11Path[i], "/75dpi") != NULL) {
313 continue;
314 }
315 if (strstr(x11Path[i], "/100dpi") != NULL) {
316 continue;
317 }
318 if (strstr(x11Path[i], "/misc") != NULL) {
319 continue;
320 }
321 if (strstr(x11Path[i], "/Speedo") != NULL) {
322 continue;
323 }
324 if (strstr(x11Path[i], ".gnome") != NULL) {
325 continue;
326 }
327#ifdef __solaris__
328 if (strstr(x11Path[i], "/F3/") != NULL) {
329 continue;
330 }
331 if (strstr(x11Path[i], "bitmap") != NULL) {
332 continue;
333 }
334#endif
335 fontdirs[pos] = strdup(x11Path[i]);
336 slen = strlen(fontdirs[pos]);
337 if (slen > 0 && fontdirs[pos][slen-1] == '/') {
338 fontdirs[pos][slen-1] = '\0'; /* null out trailing "/" */
339 }
340 pos++;
341 }
342
343 XFreeFontPath(x11Path);
344 if (pos == 0) {
345 free(fontdirs);
346 fontdirs = NULL;
347 }
348 return fontdirs;
349}
350
351
352#endif /* !HEADLESS */
353
354#ifdef __linux__
355/* from awt_LoadLibrary.c */
356JNIEXPORT jboolean JNICALL AWTIsHeadless();
357#endif
358
359/* This eliminates duplicates, at a non-linear but acceptable cost
360 * since the lists are expected to be reasonably short, and then
361 * deletes references to non-existent directories, and returns
362 * a single path consisting of unique font directories.
363 */
364static char* mergePaths(char **p1, char **p2, char **p3, jboolean noType1) {
365
366 int len1=0, len2=0, len3=0, totalLen=0, numDirs=0,
367 currLen, i, j, found, pathLen=0;
368 char **ptr, **fontdirs;
369 char *fontPath = NULL;
370
371 if (p1 != NULL) {
372 ptr = p1;
373 while (*ptr++ != NULL) len1++;
374 }
375 if (p2 != NULL) {
376 ptr = p2;
377
378 while (*ptr++ != NULL) len2++;
379 }
380 if (p3 != NULL) {
381 ptr = p3;
382 while (*ptr++ != NULL) len3++;
383 }
384 totalLen = len1+len2+len3;
385 fontdirs = (char**)calloc(totalLen, sizeof(char*));
386
387 for (i=0; i < len1; i++) {
388 if (noType1 && strstr(p1[i], "Type1") != NULL) {
389 continue;
390 }
391 fontdirs[numDirs++] = p1[i];
392 }
393
394 currLen = numDirs; /* only compare against previous path dirs */
395 for (i=0; i < len2; i++) {
396 if (noType1 && strstr(p2[i], "Type1") != NULL) {
397 continue;
398 }
399 found = 0;
400 for (j=0; j < currLen; j++) {
401 if (strcmp(fontdirs[j], p2[i]) == 0) {
402 found = 1;
403 break;
404 }
405 }
406 if (!found) {
407 fontdirs[numDirs++] = p2[i];
408 }
409 }
410
411 currLen = numDirs; /* only compare against previous path dirs */
412 for (i=0; i < len3; i++) {
413 if (noType1 && strstr(p3[i], "Type1") != NULL) {
414 continue;
415 }
416 found = 0;
417 for (j=0; j < currLen; j++) {
418 if (strcmp(fontdirs[j], p3[i]) == 0) {
419 found = 1;
420 break;
421 }
422 }
423 if (!found) {
424 fontdirs[numDirs++] = p3[i];
425 }
426 }
427
428 /* Now fontdirs contains unique dirs and numDirs records how many.
429 * What we don't know is if they all exist. On reflection I think
430 * this isn't an issue, so for now I will return all these locations,
431 * converted to one string */
432 for (i=0; i<numDirs; i++) {
433 pathLen += (strlen(fontdirs[i]) + 1);
434 }
435 if (pathLen > 0 && (fontPath = malloc(pathLen))) {
436 *fontPath = '\0';
437 for (i = 0; i<numDirs; i++) {
438 if (i != 0) {
439 strcat(fontPath, ":");
440 }
441 strcat(fontPath, fontdirs[i]);
442 }
443 }
444 free (fontdirs);
445
446 return fontPath;
447}
448
449/*
450 * The goal of this function is to find all "system" fonts which
451 * are needed by the JRE to display text in supported locales etc, and
452 * to support APIs which allow users to enumerate all system fonts and use
453 * them from their Java applications.
454 * The preferred mechanism is now using the new "fontconfig" library
455 * This exists on newer versions of Linux and Solaris (S10 and above)
456 * The library is dynamically located. The results are merged with
457 * a set of "known" locations and with the X11 font path, if running in
458 * a local X11 environment.
459 * The hardwired paths are built into the JDK binary so as new font locations
460 * are created on a host plaform for them to be located by the JRE they will
461 * need to be added ito the host's font configuration database, typically
462 * /etc/fonts/local.conf, and to ensure that directory contains a fonts.dir
463 * NB: Fontconfig also depends heavily for performance on the host O/S
464 * maintaining up to date caches.
465 * This is consistent with the requirements of the desktop environments
466 * on these OSes.
467 * This also frees us from X11 APIs as JRE is required to function in
468 * a "headless" mode where there is no Xserver.
469 */
470static char *getPlatformFontPathChars(JNIEnv *env, jboolean noType1) {
471
472 char **fcdirs = NULL, **x11dirs = NULL, **knowndirs = NULL, *path = NULL;
473
474 /* As of 1.5 we try to use fontconfig on both Solaris and Linux.
475 * If its not available NULL is returned.
476 */
477 fcdirs = getFontConfigLocations();
478
479#ifdef __linux__
480 knowndirs = fullLinuxFontPath;
481#else /* IF SOLARIS */
482 knowndirs = fullSolarisFontPath;
483#endif
484
485 /* REMIND: this code requires to be executed when the GraphicsEnvironment
486 * is already initialised. That is always true, but if it were not so,
487 * this code could throw an exception and the fontpath would fail to
488 * be initialised.
489 */
490#ifndef HEADLESS
491#ifdef __linux__ /* There's no headless build on linux ... */
492 if (!AWTIsHeadless()) { /* .. so need to call a function to check */
493#endif
494 AWT_LOCK();
495 if (isDisplayLocal(env)) {
496 x11dirs = getX11FontPath();
497 }
498 AWT_UNLOCK();
499#ifdef __linux__
500 }
501#endif
502#endif /* !HEADLESS */
503 path = mergePaths(fcdirs, x11dirs, knowndirs, noType1);
504 if (fcdirs != NULL) {
505 char **p = fcdirs;
506 while (*p != NULL) free(*p++);
507 free(fcdirs);
508 }
509
510 if (x11dirs != NULL) {
511 char **p = x11dirs;
512 while (*p != NULL) free(*p++);
513 free(x11dirs);
514 }
515
516 return path;
517}
518
519JNIEXPORT jstring JNICALL Java_sun_font_FontManager_getFontPath
520(JNIEnv *env, jclass obj, jboolean noType1) {
521 jstring ret;
522 static char *ptr = NULL; /* retain result across calls */
523
524 if (ptr == NULL) {
525 ptr = getPlatformFontPathChars(env, noType1);
526 }
527 ret = (*env)->NewStringUTF(env, ptr);
528 return ret;
529}
530
531/*
532 * In general setting the font path in a remote display situation is
533 * problematic. But for Solaris->Solaris the paths needed by the JRE should
534 * also be available to the server, although we have no way to check this
535 * for sure.
536 * So set the font path if we think its safe to do so:
537 * All Solaris X servers at least back to 2.6 and up to Solaris 10
538 * define the exact same vendor string.
539 * The version number for Solaris 2.6 is 3600, for 2.7 is 3610 and
540 * for Solaris 8 6410
541 * we want to set the font path only for 2.8 and onwards. Earlier releases
542 * are unlikely to have the right fonts and can't install "all locales"
543 * as needed to be sure. Also Solaris 8 is the earliest release supported
544 * by 1.5.
545 */
546#ifndef HEADLESS
547static int isSunXServer() {
548#ifdef __solaris__
549 return (strcmp("Sun Microsystems, Inc.", ServerVendor(awt_display)) == 0 &&
550 VendorRelease(awt_display) >= 6410);
551#else
552 return 0;
553#endif /* __solaris__ */
554}
555
556/* Avoid re-doing work for every call to setNativeFontPath */
557static int doSetFontPath = -1;
558static int shouldSetXFontPath(JNIEnv *env) {
559 if (doSetFontPath == -1) {
560 doSetFontPath =
561 awt_display != NULL && (isDisplayLocal(env) || isSunXServer());
562 }
563 return doSetFontPath;
564}
565#endif /* !HEADLESS */
566
567JNIEXPORT void JNICALL Java_sun_font_FontManager_setNativeFontPath
568(JNIEnv *env, jclass obj, jstring theString) {
569#ifdef HEADLESS
570 return;
571#else
572 fDirRecord fDir;
573 const char *theChars;
574
575 if (awt_display == NULL) {
576 return;
577 }
578 AWT_LOCK();
579 if (shouldSetXFontPath(env)) {
580 theChars = (*env)->GetStringUTFChars (env, theString, 0);
581 fDir.num = 1;
582 fDir.name[0] = theChars;
583 /* printf ("Registering the font path here %s \n", theChars ); */
584 AddFontsToX11FontPath ( &fDir );
585 if (theChars) {
586 (*env)->ReleaseStringUTFChars (env,
587 theString, (const char*)theChars);
588 }
589 }
590 AWT_UNLOCK();
591
592#endif
593}
594
595/* This isn't yet used on unix, the implementation is added since shared
596 * code calls this method in preparation for future use.
597 */
598/* Obtain all the fontname -> filename mappings.
599 * This is called once and the results returned to Java code which can
600 * use it for lookups to reduce or avoid the need to search font files.
601 */
602JNIEXPORT void JNICALL
603Java_sun_font_FontManager_populateFontFileNameMap
604(JNIEnv *env, jclass obj, jobject fontToFileMap,
605 jobject fontToFamilyMap, jobject familyToFontListMap, jobject locale)
606{
607 return;
608}
609
610#include <dlfcn.h>
611#ifndef __linux__ /* i.e. is solaris */
612#include <link.h>
613#endif
614
615#include "fontconfig.h"
616
617
618static void* openFontConfig() {
619
620 char *homeEnv;
621 static char *homeEnvStr = "HOME="; /* must be static */
622 void* libfontconfig = NULL;
623#ifdef __solaris__
624#define SYSINFOBUFSZ 8
625 char sysinfobuf[SYSINFOBUFSZ];
626#endif
627
628 /* Private workaround to not use fontconfig library.
629 * May be useful during testing/debugging
630 */
631 char *useFC = getenv("USE_J2D_FONTCONFIG");
632 if (useFC != NULL && !strcmp(useFC, "no")) {
633 return NULL;
634 }
635
636#ifdef __solaris__
637 /* fontconfig is likely not properly configured on S8/S9 - skip it,
638 * although allow user to override this behaviour with an env. variable
639 * ie if USE_J2D_FONTCONFIG=yes then we skip this test.
640 * NB "4" is the length of a string which matches our patterns.
641 */
642 if (useFC == NULL || strcmp(useFC, "yes")) {
643 if (sysinfo(SI_RELEASE, sysinfobuf, SYSINFOBUFSZ) == 4) {
644 if ((!strcmp(sysinfobuf, "5.8") || !strcmp(sysinfobuf, "5.9"))) {
645 return NULL;
646 }
647 }
648 }
649#endif
650 /* 64 bit sparc should pick up the right version from the lib path.
651 * New features may be added to libfontconfig, this is expected to
652 * be compatible with old features, but we may need to start
653 * distinguishing the library version, to know whether to expect
654 * certain symbols - and functionality - to be available.
655 * Also add explicit search for .so.1 in case .so symlink doesn't exist.
656 */
657 libfontconfig = dlopen("libfontconfig.so.1", RTLD_LOCAL|RTLD_LAZY);
658 if (libfontconfig == NULL) {
659 libfontconfig = dlopen("libfontconfig.so", RTLD_LOCAL|RTLD_LAZY);
660 if (libfontconfig == NULL) {
661 return NULL;
662 }
663 }
664
665 /* Version 1.0 of libfontconfig crashes if HOME isn't defined in
666 * the environment. This should generally never happen, but we can't
667 * control it, and can't control the version of fontconfig, so iff
668 * its not defined we set it to an empty value which is sufficient
669 * to prevent a crash. I considered unsetting it before exit, but
670 * it doesn't appear to work on Solaris, so I will leave it set.
671 */
672 homeEnv = getenv("HOME");
673 if (homeEnv == NULL) {
674 putenv(homeEnvStr);
675 }
676
677 return libfontconfig;
678}
679
680typedef void* (FcFiniFuncType)();
681
682static void closeFontConfig(void* libfontconfig, jboolean fcFini) {
683
684 /* NB FcFini is not in (eg) the Solaris 10 version of fontconfig. Its not
685 * clear if this means we are really leaking resources in those cases
686 * but it seems we should call this function when its available.
687 * But since the Swing GTK code may be still accessing the lib, its probably
688 * safest for now to just let this "leak" rather than potentially
689 * concurrently free global data still in use by other code.
690 */
691#if 0
692 if (fcFini) { /* release resources */
693 FcFiniFuncType FcFini = (FcFiniFuncType)dlsym(libfontconfig, "FcFini");
694
695 if (FcFini != NULL) {
696 (*FcFini)();
697 }
698 }
699#endif
700 dlclose(libfontconfig);
701}
702
703typedef FcConfig* (*FcInitLoadConfigFuncType)();
704typedef FcPattern* (*FcPatternBuildFuncType)(FcPattern *orig, ...);
705typedef FcObjectSet* (*FcObjectSetFuncType)(const char *first, ...);
706typedef FcFontSet* (*FcFontListFuncType)(FcConfig *config,
707 FcPattern *p,
708 FcObjectSet *os);
709typedef FcResult (*FcPatternGetBoolFuncType)(const FcPattern *p,
710 const char *object,
711 int n,
712 FcBool *b);
713typedef FcResult (*FcPatternGetIntegerFuncType)(const FcPattern *p,
714 const char *object,
715 int n,
716 int *i);
717typedef FcResult (*FcPatternGetStringFuncType)(const FcPattern *p,
718 const char *object,
719 int n,
720 FcChar8 ** s);
721typedef FcChar8* (*FcStrDirnameFuncType)(const FcChar8 *file);
722typedef void (*FcPatternDestroyFuncType)(FcPattern *p);
723typedef void (*FcFontSetDestroyFuncType)(FcFontSet *s);
724typedef FcPattern* (*FcNameParseFuncType)(const FcChar8 *name);
725typedef FcBool (*FcPatternAddStringFuncType)(FcPattern *p,
726 const char *object,
727 const FcChar8 *s);
728typedef void (*FcDefaultSubstituteFuncType)(FcPattern *p);
729typedef FcBool (*FcConfigSubstituteFuncType)(FcConfig *config,
730 FcPattern *p,
731 FcMatchKind kind);
732typedef FcPattern* (*FcFontMatchFuncType)(FcConfig *config,
733 FcPattern *p,
734 FcResult *result);
735typedef FcFontSet* (*FcFontSetCreateFuncType)();
736typedef FcBool (*FcFontSetAddFuncType)(FcFontSet *s, FcPattern *font);
737
738
739static char **getFontConfigLocations() {
740
741 char **fontdirs;
742 int numdirs = 0;
743 FcInitLoadConfigFuncType FcInitLoadConfig;
744 FcPatternBuildFuncType FcPatternBuild;
745 FcObjectSetFuncType FcObjectSetBuild;
746 FcFontListFuncType FcFontList;
747 FcPatternGetStringFuncType FcPatternGetString;
748 FcStrDirnameFuncType FcStrDirname;
749 FcPatternDestroyFuncType FcPatternDestroy;
750 FcFontSetDestroyFuncType FcFontSetDestroy;
751
752 FcConfig *fontconfig;
753 FcPattern *pattern;
754 FcObjectSet *objset;
755 FcFontSet *fontSet;
756 FcStrList *strList;
757 FcChar8 *str;
758 int i, f, found, len=0;
759 char **fontPath;
760
761 void* libfontconfig = openFontConfig();
762
763 if (libfontconfig == NULL) {
764 return NULL;
765 }
766
767 FcPatternBuild =
768 (FcPatternBuildFuncType)dlsym(libfontconfig, "FcPatternBuild");
769 FcObjectSetBuild =
770 (FcObjectSetFuncType)dlsym(libfontconfig, "FcObjectSetBuild");
771 FcFontList =
772 (FcFontListFuncType)dlsym(libfontconfig, "FcFontList");
773 FcPatternGetString =
774 (FcPatternGetStringFuncType)dlsym(libfontconfig, "FcPatternGetString");
775 FcStrDirname =
776 (FcStrDirnameFuncType)dlsym(libfontconfig, "FcStrDirname");
777 FcPatternDestroy =
778 (FcPatternDestroyFuncType)dlsym(libfontconfig, "FcPatternDestroy");
779 FcFontSetDestroy =
780 (FcFontSetDestroyFuncType)dlsym(libfontconfig, "FcFontSetDestroy");
781
782 if (FcPatternBuild == NULL ||
783 FcObjectSetBuild == NULL ||
784 FcPatternGetString == NULL ||
785 FcFontList == NULL ||
786 FcStrDirname == NULL ||
787 FcPatternDestroy == NULL ||
788 FcFontSetDestroy == NULL) { /* problem with the library: return. */
789 closeFontConfig(libfontconfig, JNI_FALSE);
790 return NULL;
791 }
792
793 /* Make calls into the fontconfig library to build a search for
794 * outline fonts, and to get the set of full file paths from the matches.
795 * This set is returned from the call to FcFontList(..)
796 * We allocate an array of char* pointers sufficient to hold all
797 * the matches + 1 extra which ensures there will be a NULL after all
798 * valid entries.
799 * We call FcStrDirname strip the file name from the path, and
800 * check if we have yet seen this directory. If not we add a pointer to
801 * it into our array of char*. Note that FcStrDirname returns newly
802 * allocated storage so we can use this in the return char** value.
803 * Finally we clean up, freeing allocated resources, and return the
804 * array of unique directories.
805 */
806 pattern = (*FcPatternBuild)(NULL, FC_OUTLINE, FcTypeBool, FcTrue, NULL);
807 objset = (*FcObjectSetBuild)(FC_FILE, NULL);
808 fontSet = (*FcFontList)(NULL, pattern, objset);
809 fontdirs = (char**)calloc(fontSet->nfont+1, sizeof(char*));
810 for (f=0; f < fontSet->nfont; f++) {
811 FcChar8 *file;
812 FcChar8 *dir;
813 if ((*FcPatternGetString)(fontSet->fonts[f], FC_FILE, 0, &file) ==
814 FcResultMatch) {
815 dir = (*FcStrDirname)(file);
816 found = 0;
817 for (i=0;i<numdirs; i++) {
818 if (strcmp(fontdirs[i], (char*)dir) == 0) {
819 found = 1;
820 break;
821 }
822 }
823 if (!found) {
824 fontdirs[numdirs++] = (char*)dir;
825 } else {
826 free((char*)dir);
827 }
828 }
829 }
830
831 /* Free memory and close the ".so" */
832 (*FcFontSetDestroy)(fontSet);
833 (*FcPatternDestroy)(pattern);
834 closeFontConfig(libfontconfig, JNI_TRUE);
835 return fontdirs;
836}
837
838/* These are copied from sun.awt.SunHints.
839 * Consider initialising them as ints using JNI for more robustness.
840 */
841#define TEXT_AA_OFF 1
842#define TEXT_AA_ON 2
843#define TEXT_AA_LCD_HRGB 4
844#define TEXT_AA_LCD_HBGR 5
845#define TEXT_AA_LCD_VRGB 6
846#define TEXT_AA_LCD_VBGR 7
847
848JNIEXPORT jint JNICALL
849Java_sun_font_FontManager_getFontConfigAASettings
850(JNIEnv *env, jclass obj, jstring localeStr, jstring fcNameStr) {
851
852 FcNameParseFuncType FcNameParse;
853 FcPatternAddStringFuncType FcPatternAddString;
854 FcConfigSubstituteFuncType FcConfigSubstitute;
855 FcDefaultSubstituteFuncType FcDefaultSubstitute;
856 FcFontMatchFuncType FcFontMatch;
857 FcPatternGetBoolFuncType FcPatternGetBool;
858 FcPatternGetIntegerFuncType FcPatternGetInteger;
859 FcPatternDestroyFuncType FcPatternDestroy;
860
861 FcPattern *pattern, *matchPattern;
862 FcResult result;
863 FcBool antialias = FcFalse;
864 int rgba = 0;
865 const char *locale=NULL, *fcName=NULL;
866 void* libfontconfig;
867
868 if (fcNameStr == NULL || localeStr == NULL) {
869 return -1;
870 }
871
872 fcName = (*env)->GetStringUTFChars(env, fcNameStr, 0);
873 if (fcName == NULL) {
874 return -1;
875 }
876 locale = (*env)->GetStringUTFChars(env, localeStr, 0);
877
878 if ((libfontconfig = openFontConfig()) == NULL) {
879 (*env)->ReleaseStringUTFChars (env, fcNameStr, (const char*)fcName);
880 if (locale) {
881 (*env)->ReleaseStringUTFChars (env, localeStr,(const char*)locale);
882 }
883 return -1;
884 }
885
886 FcNameParse = (FcNameParseFuncType)dlsym(libfontconfig, "FcNameParse");
887 FcPatternAddString =
888 (FcPatternAddStringFuncType)dlsym(libfontconfig, "FcPatternAddString");
889 FcConfigSubstitute =
890 (FcConfigSubstituteFuncType)dlsym(libfontconfig, "FcConfigSubstitute");
891 FcDefaultSubstitute = (FcDefaultSubstituteFuncType)
892 dlsym(libfontconfig, "FcDefaultSubstitute");
893 FcFontMatch = (FcFontMatchFuncType)dlsym(libfontconfig, "FcFontMatch");
894 FcPatternGetBool = (FcPatternGetBoolFuncType)
895 dlsym(libfontconfig, "FcPatternGetBool");
896 FcPatternGetInteger = (FcPatternGetIntegerFuncType)
897 dlsym(libfontconfig, "FcPatternGetInteger");
898 FcPatternDestroy =
899 (FcPatternDestroyFuncType)dlsym(libfontconfig, "FcPatternDestroy");
900
901 if (FcNameParse == NULL ||
902 FcPatternAddString == NULL ||
903 FcConfigSubstitute == NULL ||
904 FcDefaultSubstitute == NULL ||
905 FcFontMatch == NULL ||
906 FcPatternGetBool == NULL ||
907 FcPatternGetInteger == NULL ||
908 FcPatternDestroy == NULL) { /* problem with the library: return. */
909
910 (*env)->ReleaseStringUTFChars (env, fcNameStr, (const char*)fcName);
911 if (locale) {
912 (*env)->ReleaseStringUTFChars (env, localeStr,(const char*)locale);
913 }
914 closeFontConfig(libfontconfig, JNI_FALSE);
915 return -1;
916 }
917
918
919 pattern = (*FcNameParse)((FcChar8 *)fcName);
920 if (locale != NULL) {
921 (*FcPatternAddString)(pattern, FC_LANG, (unsigned char*)locale);
922 }
923 (*FcConfigSubstitute)(NULL, pattern, FcMatchPattern);
924 (*FcDefaultSubstitute)(pattern);
925 matchPattern = (*FcFontMatch)(NULL, pattern, &result);
926 /* Perhaps should call FcFontRenderPrepare() here as some pattern
927 * elements might change as a result of that call, but I'm not seeing
928 * any difference in testing.
929 */
930 if (matchPattern) {
931 (*FcPatternGetBool)(matchPattern, FC_ANTIALIAS, 0, &antialias);
932 (*FcPatternGetInteger)(matchPattern, FC_RGBA, 0, &rgba);
933 (*FcPatternDestroy)(matchPattern);
934 }
935 (*FcPatternDestroy)(pattern);
936
937 (*env)->ReleaseStringUTFChars (env, fcNameStr, (const char*)fcName);
938 if (locale) {
939 (*env)->ReleaseStringUTFChars (env, localeStr, (const char*)locale);
940 }
941 closeFontConfig(libfontconfig, JNI_TRUE);
942
943 if (antialias == FcFalse) {
944 return TEXT_AA_OFF;
945 } else if (rgba <= FC_RGBA_UNKNOWN || rgba >= FC_RGBA_NONE) {
946 return TEXT_AA_ON;
947 } else {
948 switch (rgba) {
949 case FC_RGBA_RGB : return TEXT_AA_LCD_HRGB;
950 case FC_RGBA_BGR : return TEXT_AA_LCD_HBGR;
951 case FC_RGBA_VRGB : return TEXT_AA_LCD_VRGB;
952 case FC_RGBA_VBGR : return TEXT_AA_LCD_VBGR;
953 default : return TEXT_AA_LCD_HRGB; // should not get here.
954 }
955 }
956}
957
958
959JNIEXPORT void JNICALL
960Java_sun_font_FontManager_getFontConfig
961(JNIEnv *env, jclass obj, jstring localeStr, jobjectArray fontInfoArray) {
962
963 FcNameParseFuncType FcNameParse;
964 FcPatternAddStringFuncType FcPatternAddString;
965 FcConfigSubstituteFuncType FcConfigSubstitute;
966 FcDefaultSubstituteFuncType FcDefaultSubstitute;
967 FcFontMatchFuncType FcFontMatch;
968 FcPatternGetStringFuncType FcPatternGetString;
969 FcPatternDestroyFuncType FcPatternDestroy;
970
971 int i, arrlen;
972 jobject fontInfoObj;
973 jstring fcNameStr, jstr;
974 const char *locale, *fcName;
975 FcPattern *pattern, *matchPattern;
976 FcResult result;
977 void* libfontconfig;
978 jfieldID fcNameID, familyNameID, fontFileID;
979
980 jclass fontInfoArrayClass =
981 (*env)->FindClass(env, "[Lsun/font/FontManager$FontConfigInfo;");
982 jclass fontInfoClass =
983 (*env)->FindClass(env, "sun/font/FontManager$FontConfigInfo");
984
985 if (fontInfoArray == NULL || fontInfoClass == NULL) {
986 return;
987 }
988
989 fcNameID = (*env)->GetFieldID(env, fontInfoClass,
990 "fcName", "Ljava/lang/String;");
991 familyNameID = (*env)->GetFieldID(env, fontInfoClass,
992 "familyName", "Ljava/lang/String;");
993 fontFileID = (*env)->GetFieldID(env, fontInfoClass,
994 "fontFile", "Ljava/lang/String;");
995
996 if (fcNameID == NULL || familyNameID == NULL || fontFileID == NULL) {
997 return;
998 }
999
1000 if ((libfontconfig = openFontConfig()) == NULL) {
1001 return;
1002 }
1003
1004 FcNameParse = (FcNameParseFuncType)dlsym(libfontconfig, "FcNameParse");
1005 FcPatternAddString =
1006 (FcPatternAddStringFuncType)dlsym(libfontconfig, "FcPatternAddString");
1007 FcConfigSubstitute =
1008 (FcConfigSubstituteFuncType)dlsym(libfontconfig, "FcConfigSubstitute");
1009 FcDefaultSubstitute = (FcDefaultSubstituteFuncType)
1010 dlsym(libfontconfig, "FcDefaultSubstitute");
1011 FcFontMatch = (FcFontMatchFuncType)dlsym(libfontconfig, "FcFontMatch");
1012 FcPatternGetString =
1013 (FcPatternGetStringFuncType)dlsym(libfontconfig, "FcPatternGetString");
1014 FcPatternDestroy =
1015 (FcPatternDestroyFuncType)dlsym(libfontconfig, "FcPatternDestroy");
1016
1017 if (FcNameParse == NULL ||
1018 FcPatternAddString == NULL ||
1019 FcConfigSubstitute == NULL ||
1020 FcDefaultSubstitute == NULL ||
1021 FcFontMatch == NULL ||
1022 FcPatternGetString == NULL ||
1023 FcPatternDestroy == NULL) { /* problem with the library: return. */
1024 closeFontConfig(libfontconfig, JNI_FALSE);
1025 return;
1026 }
1027
1028 locale = (*env)->GetStringUTFChars(env, localeStr, 0);
1029
1030 arrlen = (*env)->GetArrayLength(env, fontInfoArray);
1031 for (i=0; i<arrlen; i++) {
1032 fontInfoObj = (*env)->GetObjectArrayElement(env, fontInfoArray, i);
1033 fcNameStr =
1034 (jstring)((*env)->GetObjectField(env, fontInfoObj, fcNameID));
1035 fcName = (*env)->GetStringUTFChars(env, fcNameStr, 0);
1036 if (fcName == NULL) {
1037 continue;
1038 }
1039 pattern = (*FcNameParse)((FcChar8 *)fcName);
1040 /* locale may not usually be necessary as fontconfig appears to apply
1041 * this anyway based on the user's environment. However we want
1042 * to use the value of the JDK startup locale so this should take
1043 * care of it.
1044 */
1045 if (locale != NULL) {
1046 (*FcPatternAddString)(pattern, FC_LANG, (unsigned char*)locale);
1047 }
1048 (*FcConfigSubstitute)(NULL, pattern, FcMatchPattern);
1049 (*FcDefaultSubstitute)(pattern);
1050 matchPattern = (*FcFontMatch)(NULL, pattern, &result);
1051 if (matchPattern) {
1052 FcChar8 *file, *family;
1053
1054 (*FcPatternGetString)(matchPattern, FC_FILE, 0, &file);
1055 (*FcPatternGetString)(matchPattern, FC_FAMILY, 0, &family);
1056
1057 if (file != NULL) {
1058 jstr = (*env)->NewStringUTF(env, (const char*)file);
1059 ((*env)->SetObjectField(env, fontInfoObj, fontFileID, jstr));
1060 }
1061 if (family != NULL) {
1062 jstr = (*env)->NewStringUTF(env, (const char*)family);
1063 ((*env)->SetObjectField(env, fontInfoObj, familyNameID, jstr));
1064 }
1065 (*FcPatternDestroy)(matchPattern);
1066 }
1067 (*env)->ReleaseStringUTFChars (env, fcNameStr, (const char*)fcName);
1068 (*FcPatternDestroy)(pattern);
1069 }
1070
1071 /* release resources and close the ".so" */
1072
1073 if (locale) {
1074 (*env)->ReleaseStringUTFChars (env, localeStr, (const char*)locale);
1075 }
1076 closeFontConfig(libfontconfig, JNI_TRUE);
1077}