1/*
2 * Copyright (c) 1998, 2016, 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
59extern 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 */
79static 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 */
121static 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)
138static 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
145static char **getFontConfigLocations();
146
147typedef 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 */
157jboolean 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
191static 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
325static 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 */
393JNIEXPORT 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 */
401static 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 */
507static 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
567JNIEXPORT 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.h"
582
583
584static 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
666typedef void* (FcFiniFuncType)();
667
668static 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
689typedef FcConfig* (*FcInitLoadConfigFuncType)();
690typedef FcPattern* (*FcPatternBuildFuncType)(FcPattern *orig, ...);
691typedef FcObjectSet* (*FcObjectSetFuncType)(const char *first, ...);
692typedef FcFontSet* (*FcFontListFuncType)(FcConfig *config,
693                                         FcPattern *p,
694                                         FcObjectSet *os);
695typedef FcResult (*FcPatternGetBoolFuncType)(const FcPattern *p,
696                                               const char *object,
697                                               int n,
698                                               FcBool *b);
699typedef FcResult (*FcPatternGetIntegerFuncType)(const FcPattern *p,
700                                                const char *object,
701                                                int n,
702                                                int *i);
703typedef FcResult (*FcPatternGetStringFuncType)(const FcPattern *p,
704                                               const char *object,
705                                               int n,
706                                               FcChar8 ** s);
707typedef FcChar8* (*FcStrDirnameFuncType)(const FcChar8 *file);
708typedef void (*FcPatternDestroyFuncType)(FcPattern *p);
709typedef void (*FcFontSetDestroyFuncType)(FcFontSet *s);
710typedef FcPattern* (*FcNameParseFuncType)(const FcChar8 *name);
711typedef FcBool (*FcPatternAddStringFuncType)(FcPattern *p,
712                                             const char *object,
713                                             const FcChar8 *s);
714typedef void (*FcDefaultSubstituteFuncType)(FcPattern *p);
715typedef FcBool (*FcConfigSubstituteFuncType)(FcConfig *config,
716                                             FcPattern *p,
717                                             FcMatchKind kind);
718typedef FcPattern* (*FcFontMatchFuncType)(FcConfig *config,
719                                          FcPattern *p,
720                                          FcResult *result);
721typedef FcFontSet* (*FcFontSetCreateFuncType)();
722typedef FcBool (*FcFontSetAddFuncType)(FcFontSet *s, FcPattern *font);
723
724typedef FcResult (*FcPatternGetCharSetFuncType)(FcPattern *p,
725                                                const char *object,
726                                                int n,
727                                                FcCharSet **c);
728typedef FcFontSet* (*FcFontSortFuncType)(FcConfig *config,
729                                         FcPattern *p,
730                                         FcBool trim,
731                                         FcCharSet **csp,
732                                         FcResult *result);
733typedef FcCharSet* (*FcCharSetUnionFuncType)(const FcCharSet *a,
734                                             const FcCharSet *b);
735typedef FcChar32 (*FcCharSetSubtractCountFuncType)(const FcCharSet *a,
736                                                   const FcCharSet *b);
737
738typedef int (*FcGetVersionFuncType)();
739
740typedef FcStrList* (*FcConfigGetCacheDirsFuncType)(FcConfig *config);
741typedef FcChar8* (*FcStrListNextFuncType)(FcStrList *list);
742typedef FcChar8* (*FcStrListDoneFuncType)(FcStrList *list);
743
744static 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
859JNIEXPORT jint JNICALL
860Java_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
969JNIEXPORT jint JNICALL
970Java_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
994JNIEXPORT void JNICALL
995Java_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#endif
1258             ) {
1259                continue;
1260            }
1261            result = (*FcPatternGetCharSet)(fontPattern,
1262                                            FC_CHARSET, 0, &charset);
1263            if (result != FcResultMatch) {
1264                free(family);
1265                free(fullname);
1266                free(styleStr);
1267                free(file);
1268                (*FcPatternDestroy)(pattern);
1269                (*FcFontSetDestroy)(fontset);
1270                closeFontConfig(libfontconfig, JNI_FALSE);
1271                return;
1272            }
1273
1274            /* We don't want 20 or 30 fonts, so once we hit 10 fonts,
1275             * then require that they really be adding value. Too many
1276             * adversely affects load time for minimal value-add.
1277             * This is still likely far more than we've had in the past.
1278             */
1279            if (j==10) {
1280                minGlyphs = 50;
1281            }
1282            if (unionCharset == NULL) {
1283                unionCharset = charset;
1284            } else {
1285                if ((*FcCharSetSubtractCount)(charset, unionCharset)
1286                    > minGlyphs) {
1287                    unionCharset = (* FcCharSetUnion)(unionCharset, charset);
1288                } else {
1289                    continue;
1290                }
1291            }
1292
1293            fontCount++; // found a font we will use.
1294            (*FcPatternGetString)(fontPattern, FC_FILE, 0, &file[j]);
1295            (*FcPatternGetString)(fontPattern, FC_FAMILY, 0, &family[j]);
1296            (*FcPatternGetString)(fontPattern, FC_STYLE, 0, &styleStr[j]);
1297            (*FcPatternGetString)(fontPattern, FC_FULLNAME, 0, &fullname[j]);
1298            if (!includeFallbacks) {
1299                break;
1300            }
1301            if (fontCount == 254) {
1302                break; // CompositeFont will only use up to 254 slots from here.
1303            }
1304        }
1305
1306        /* Once we get here 'fontCount' is the number of returned fonts
1307         * we actually want to use, so we create 'fcFontArr' of that length.
1308         * The non-null entries of "family[]" etc are those fonts.
1309         * Then loop again over all nfonts adding just those non-null ones
1310         * to 'fcFontArr'. If its null (we didn't want the font)
1311         * then we don't enter the main body.
1312         * So we should never get more than 'fontCount' entries.
1313         */
1314        if (includeFallbacks) {
1315            fcFontArr =
1316                (*env)->NewObjectArray(env, fontCount, fcFontClass, NULL);
1317            if (IS_NULL(fcFontArr)) {
1318                free(family);
1319                free(fullname);
1320                free(styleStr);
1321                free(file);
1322                (*FcPatternDestroy)(pattern);
1323                (*FcFontSetDestroy)(fontset);
1324                closeFontConfig(libfontconfig, JNI_FALSE);
1325                return;
1326            }
1327            (*env)->SetObjectField(env,fcCompFontObj, fcAllFontsID, fcFontArr);
1328        }
1329        fn=0;
1330
1331        for (j=0;j<nfonts;j++) {
1332            if (family[j] != NULL) {
1333                jobject fcFont =
1334                    (*env)->NewObject(env, fcFontClass, fcFontCons);
1335                if (IS_NULL(fcFont)) break;
1336                jstr = (*env)->NewStringUTF(env, (const char*)family[j]);
1337                if (IS_NULL(jstr)) break;
1338                (*env)->SetObjectField(env, fcFont, familyNameID, jstr);
1339                (*env)->DeleteLocalRef(env, jstr);
1340                if (file[j] != NULL) {
1341                    jstr = (*env)->NewStringUTF(env, (const char*)file[j]);
1342                    if (IS_NULL(jstr)) break;
1343                    (*env)->SetObjectField(env, fcFont, fontFileID, jstr);
1344                    (*env)->DeleteLocalRef(env, jstr);
1345                }
1346                if (styleStr[j] != NULL) {
1347                    jstr = (*env)->NewStringUTF(env, (const char*)styleStr[j]);
1348                    if (IS_NULL(jstr)) break;
1349                    (*env)->SetObjectField(env, fcFont, styleNameID, jstr);
1350                    (*env)->DeleteLocalRef(env, jstr);
1351                }
1352                if (fullname[j] != NULL) {
1353                    jstr = (*env)->NewStringUTF(env, (const char*)fullname[j]);
1354                    if (IS_NULL(jstr)) break;
1355                    (*env)->SetObjectField(env, fcFont, fullNameID, jstr);
1356                    (*env)->DeleteLocalRef(env, jstr);
1357                }
1358                if (fn==0) {
1359                    (*env)->SetObjectField(env, fcCompFontObj,
1360                                           fcFirstFontID, fcFont);
1361                }
1362                if (includeFallbacks) {
1363                    (*env)->SetObjectArrayElement(env, fcFontArr, fn++,fcFont);
1364                } else {
1365                    (*env)->DeleteLocalRef(env, fcFont);
1366                    break;
1367                }
1368                (*env)->DeleteLocalRef(env, fcFont);
1369            }
1370        }
1371        if (includeFallbacks) {
1372            (*env)->DeleteLocalRef(env, fcFontArr);
1373        }
1374        (*env)->DeleteLocalRef(env, fcCompFontObj);
1375        (*FcFontSetDestroy)(fontset);
1376        (*FcPatternDestroy)(pattern);
1377        free(family);
1378        free(styleStr);
1379        free(fullname);
1380        free(file);
1381    }
1382
1383    /* release resources and close the ".so" */
1384
1385    if (locale) {
1386        (*env)->ReleaseStringUTFChars (env, localeStr, (const char*)locale);
1387    }
1388    closeFontConfig(libfontconfig, JNI_TRUE);
1389}
1390