Path: blob/master/src/java.desktop/unix/native/common/awt/fontpath.c
41153 views
/*1* Copyright (c) 1998, 2020, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425#if defined(__linux__)26#include <string.h>27#endif /* __linux__ */28#include <stdio.h>29#include <stdlib.h>30#include <strings.h>31#include <sys/types.h>32#include <sys/stat.h>33#include <sys/mman.h>34#include <fcntl.h>35#include <unistd.h>3637#include <jni.h>38#include <jni_util.h>39#include <jvm_md.h>40#include <sizecalc.h>41#ifndef HEADLESS42#include <X11/Xlib.h>43#include <awt.h>44#else45/* locks ought to be included from awt.h */46#define AWT_LOCK()47#define AWT_UNLOCK()48#endif /* !HEADLESS */4950#if defined(__linux__) && !defined(MAP_FAILED)51#define MAP_FAILED ((caddr_t)-1)52#endif5354#ifndef HEADLESS55extern Display *awt_display;56#endif /* !HEADLESS */5758#define FONTCONFIG_DLL_VERSIONED VERSIONED_JNI_LIB_NAME("fontconfig", "1")59#define FONTCONFIG_DLL JNI_LIB_NAME("fontconfig")6061#define MAXFDIRS 512 /* Max number of directories that contain fonts */6263#if defined( __linux__)64/* All the known interesting locations we have discovered on65* various flavors of Linux66*/67static char *fullLinuxFontPath[] = {68"/usr/X11R6/lib/X11/fonts/TrueType", /* RH 7.1+ */69"/usr/X11R6/lib/X11/fonts/truetype", /* SuSE */70"/usr/X11R6/lib/X11/fonts/tt",71"/usr/X11R6/lib/X11/fonts/TTF",72"/usr/X11R6/lib/X11/fonts/OTF", /* RH 9.0 (but empty!) */73"/usr/share/fonts/ja/TrueType", /* RH 7.2+ */74"/usr/share/fonts/truetype",75"/usr/share/fonts/ko/TrueType", /* RH 9.0 */76"/usr/share/fonts/zh_CN/TrueType", /* RH 9.0 */77"/usr/share/fonts/zh_TW/TrueType", /* RH 9.0 */78"/var/lib/defoma/x-ttcidfont-conf.d/dirs/TrueType", /* Debian */79"/usr/X11R6/lib/X11/fonts/Type1",80"/usr/share/fonts/default/Type1", /* RH 9.0 */81NULL, /* terminates the list */82};83#elif defined(_AIX)84static char *fullAixFontPath[] = {85"/usr/lpp/X11/lib/X11/fonts/Type1", /* from X11.fnt.iso_T1 */86"/usr/lpp/X11/lib/X11/fonts/TrueType", /* from X11.fnt.ucs.ttf */87NULL, /* terminates the list */88};89#endif9091static char **getFontConfigLocations();9293typedef struct {94const char *name[MAXFDIRS];95int num;96} fDirRecord, *fDirRecordPtr;9798#ifndef HEADLESS99100/*101* Returns True if display is local, False of it's remote.102*/103jboolean isDisplayLocal(JNIEnv *env) {104static jboolean isLocal = False;105static jboolean isLocalSet = False;106jboolean ret;107108if (! isLocalSet) {109jclass geCls = (*env)->FindClass(env, "java/awt/GraphicsEnvironment");110CHECK_NULL_RETURN(geCls, JNI_FALSE);111jmethodID getLocalGE = (*env)->GetStaticMethodID(env, geCls,112"getLocalGraphicsEnvironment",113"()Ljava/awt/GraphicsEnvironment;");114CHECK_NULL_RETURN(getLocalGE, JNI_FALSE);115jobject ge = (*env)->CallStaticObjectMethod(env, geCls, getLocalGE);116JNU_CHECK_EXCEPTION_RETURN(env, JNI_FALSE);117118jclass sgeCls = (*env)->FindClass(env,119"sun/java2d/SunGraphicsEnvironment");120CHECK_NULL_RETURN(sgeCls, JNI_FALSE);121if ((*env)->IsInstanceOf(env, ge, sgeCls)) {122jmethodID isDisplayLocal = (*env)->GetMethodID(env, sgeCls,123"isDisplayLocal",124"()Z");125JNU_CHECK_EXCEPTION_RETURN(env, JNI_FALSE);126isLocal = (*env)->CallBooleanMethod(env, ge, isDisplayLocal);127JNU_CHECK_EXCEPTION_RETURN(env, JNI_FALSE);128} else {129isLocal = True;130}131isLocalSet = True;132}133134return isLocal;135}136137static void AddFontsToX11FontPath ( fDirRecord *fDirP )138{139char *onePath;140int index, nPaths;141int origNumPaths, length;142int origIndex;143int totalDirCount;144char **origFontPath;145char **tempFontPath;146int doNotAppend;147int *appendDirList;148char **newFontPath;149int err, compareLength;150char fontDirPath[512];151int dirFile;152153doNotAppend = 0;154155if ( fDirP->num == 0 ) return;156157appendDirList = SAFE_SIZE_ARRAY_ALLOC(malloc, fDirP->num, sizeof ( int ));158if ( appendDirList == NULL ) {159return; /* if it fails we cannot do much */160}161162origFontPath = XGetFontPath ( awt_display, &nPaths );163164totalDirCount = nPaths;165origNumPaths = nPaths;166tempFontPath = origFontPath;167168169for (index = 0; index < fDirP->num; index++ ) {170171doNotAppend = 0;172173tempFontPath = origFontPath;174for ( origIndex = 0; origIndex < nPaths; origIndex++ ) {175176onePath = *tempFontPath;177178compareLength = strlen ( onePath );179if ( onePath[compareLength -1] == '/' )180compareLength--;181182/* there is a slash at the end of every solaris X11 font path name */183if ( strncmp ( onePath, fDirP->name[index], compareLength ) == 0 ) {184doNotAppend = 1;185break;186}187tempFontPath++;188}189190appendDirList[index] = 0;191if ( doNotAppend == 0 ) {192snprintf(fontDirPath, sizeof(fontDirPath), "%s/fonts.dir", fDirP->name[index]);193fontDirPath[sizeof(fontDirPath) - 1] = '\0';194dirFile = open ( fontDirPath, O_RDONLY, 0 );195if ( dirFile == -1 ) {196doNotAppend = 1;197} else {198close ( dirFile );199totalDirCount++;200appendDirList[index] = 1;201}202}203204}205206/* if no changes are required do not bother to do a setfontpath */207if ( totalDirCount == nPaths ) {208free ( ( void *) appendDirList );209XFreeFontPath ( origFontPath );210return;211}212213214newFontPath = SAFE_SIZE_ARRAY_ALLOC(malloc, totalDirCount, sizeof(char *));215/* if it fails free things and get out */216if ( newFontPath == NULL ) {217free ( ( void *) appendDirList );218XFreeFontPath ( origFontPath );219return;220}221222for ( origIndex = 0; origIndex < nPaths; origIndex++ ) {223onePath = origFontPath[origIndex];224newFontPath[origIndex] = onePath;225}226227/* now add the other font paths */228229for (index = 0; index < fDirP->num; index++ ) {230231if ( appendDirList[index] == 1 ) {232233/* printf ( "Appending %s\n", fDirP->name[index] ); */234235onePath = SAFE_SIZE_ARRAY_ALLOC(malloc, strlen (fDirP->name[index]) + 2, sizeof( char ) );236if (onePath == NULL) {237free ( ( void *) appendDirList );238239for ( index = origIndex; index < nPaths; index++ ) {240free( newFontPath[index] );241}242243free( ( void *) newFontPath);244XFreeFontPath ( origFontPath );245return;246}247strcpy ( onePath, fDirP->name[index] );248strcat ( onePath, "/" );249newFontPath[nPaths++] = onePath;250/* printf ( "The path to be appended is %s\n", onePath ); */251}252}253254/* printf ( "The dir count = %d\n", totalDirCount ); */255free ( ( void *) appendDirList );256257XSetFontPath ( awt_display, newFontPath, totalDirCount );258259for ( index = origNumPaths; index < totalDirCount; index++ ) {260free( newFontPath[index] );261}262263free ( (void *) newFontPath );264XFreeFontPath ( origFontPath );265return;266}267#endif /* !HEADLESS */268269270#ifndef HEADLESS271static char **getX11FontPath ()272{273char **x11Path, **fontdirs;274int i, pos, slen, nPaths, numDirs;275276x11Path = XGetFontPath (awt_display, &nPaths);277278/* This isn't ever going to be perfect: the font path may contain279* much we aren't interested in, but the cost should be moderate280* Exclude all directories that contain the strings "Speedo","/F3/",281* "75dpi", "100dpi", "misc" or "bitmap", or don't begin with a "/",282* the last of which should exclude font servers.283* Also exclude the user specific ".gnome*" directories which284* aren't going to contain the system fonts we need.285* Hopefully we are left only with Type1 and TrueType directories.286* It doesn't matter much if there are extraneous directories, it'll just287* cost us a little wasted effort upstream.288*/289fontdirs = (char**)calloc(nPaths+1, sizeof(char*));290if (fontdirs == NULL) {291return NULL;292}293pos = 0;294for (i=0; i < nPaths; i++) {295if (x11Path[i][0] != '/') {296continue;297}298if (strstr(x11Path[i], "/75dpi") != NULL) {299continue;300}301if (strstr(x11Path[i], "/100dpi") != NULL) {302continue;303}304if (strstr(x11Path[i], "/misc") != NULL) {305continue;306}307if (strstr(x11Path[i], "/Speedo") != NULL) {308continue;309}310if (strstr(x11Path[i], ".gnome") != NULL) {311continue;312}313fontdirs[pos] = strdup(x11Path[i]);314slen = strlen(fontdirs[pos]);315if (slen > 0 && fontdirs[pos][slen-1] == '/') {316fontdirs[pos][slen-1] = '\0'; /* null out trailing "/" */317}318pos++;319}320321XFreeFontPath(x11Path);322if (pos == 0) {323free(fontdirs);324fontdirs = NULL;325}326return fontdirs;327}328329330#endif /* !HEADLESS */331332#if defined(__linux__)333/* from awt_LoadLibrary.c */334JNIEXPORT jboolean JNICALL AWTIsHeadless();335#endif336337/* This eliminates duplicates, at a non-linear but acceptable cost338* since the lists are expected to be reasonably short, and then339* deletes references to non-existent directories, and returns340* a single path consisting of unique font directories.341*/342static char* mergePaths(char **p1, char **p2, char **p3, jboolean noType1) {343344int len1=0, len2=0, len3=0, totalLen=0, numDirs=0,345currLen, i, j, found, pathLen=0;346char **ptr, **fontdirs;347char *fontPath = NULL;348349if (p1 != NULL) {350ptr = p1;351while (*ptr++ != NULL) len1++;352}353if (p2 != NULL) {354ptr = p2;355356while (*ptr++ != NULL) len2++;357}358if (p3 != NULL) {359ptr = p3;360while (*ptr++ != NULL) len3++;361}362totalLen = len1+len2+len3;363fontdirs = (char**)calloc(totalLen, sizeof(char*));364if (fontdirs == NULL) {365return NULL;366}367368for (i=0; i < len1; i++) {369if (noType1 && strstr(p1[i], "Type1") != NULL) {370continue;371}372fontdirs[numDirs++] = p1[i];373}374375currLen = numDirs; /* only compare against previous path dirs */376for (i=0; i < len2; i++) {377if (noType1 && strstr(p2[i], "Type1") != NULL) {378continue;379}380found = 0;381for (j=0; j < currLen; j++) {382if (strcmp(fontdirs[j], p2[i]) == 0) {383found = 1;384break;385}386}387if (!found) {388fontdirs[numDirs++] = p2[i];389}390}391392currLen = numDirs; /* only compare against previous path dirs */393for (i=0; i < len3; i++) {394if (noType1 && strstr(p3[i], "Type1") != NULL) {395continue;396}397found = 0;398for (j=0; j < currLen; j++) {399if (strcmp(fontdirs[j], p3[i]) == 0) {400found = 1;401break;402}403}404if (!found) {405fontdirs[numDirs++] = p3[i];406}407}408409/* Now fontdirs contains unique dirs and numDirs records how many.410* What we don't know is if they all exist. On reflection I think411* this isn't an issue, so for now I will return all these locations,412* converted to one string */413for (i=0; i<numDirs; i++) {414pathLen += (strlen(fontdirs[i]) + 1);415}416if (pathLen > 0 && (fontPath = malloc(pathLen))) {417*fontPath = '\0';418for (i = 0; i<numDirs; i++) {419if (i != 0) {420strcat(fontPath, ":");421}422strcat(fontPath, fontdirs[i]);423}424}425free (fontdirs);426427return fontPath;428}429430/*431* The goal of this function is to find all "system" fonts which432* are needed by the JRE to display text in supported locales etc, and433* to support APIs which allow users to enumerate all system fonts and use434* them from their Java applications.435* The preferred mechanism is now using the new "fontconfig" library436* This exists on newer versions of Linux and Solaris (S10 and above)437* The library is dynamically located. The results are merged with438* a set of "known" locations and with the X11 font path, if running in439* a local X11 environment.440* The hardwired paths are built into the JDK binary so as new font locations441* are created on a host plaform for them to be located by the JRE they will442* need to be added ito the host's font configuration database, typically443* /etc/fonts/local.conf, and to ensure that directory contains a fonts.dir444* NB: Fontconfig also depends heavily for performance on the host O/S445* maintaining up to date caches.446* This is consistent with the requirements of the desktop environments447* on these OSes.448* This also frees us from X11 APIs as JRE is required to function in449* a "headless" mode where there is no Xserver.450*/451static char *getPlatformFontPathChars(JNIEnv *env, jboolean noType1, jboolean isX11) {452453char **fcdirs = NULL, **x11dirs = NULL, **knowndirs = NULL, *path = NULL;454455/* As of 1.5 we try to use fontconfig on both Solaris and Linux.456* If its not available NULL is returned.457*/458fcdirs = getFontConfigLocations();459460#if defined(__linux__)461knowndirs = fullLinuxFontPath;462#elif defined(_AIX)463knowndirs = fullAixFontPath;464#endif465/* REMIND: this code requires to be executed when the GraphicsEnvironment466* is already initialised. That is always true, but if it were not so,467* this code could throw an exception and the fontpath would fail to468* be initialised.469*/470#ifndef HEADLESS471if (isX11) { // The following only works in an x11 environment.472#if defined(__linux__)473/* There's no headless build on linux ... */474if (!AWTIsHeadless()) { /* .. so need to call a function to check */475#endif476/* Using the X11 font path to locate font files is now a fallback477* useful only if fontconfig failed, or is incomplete. So we could478* remove this code completely and the consequences should be rare479* and non-fatal. If this happens, then the calling Java code can480* be modified to no longer require that the AWT lock (the X11GE)481* be initialised prior to calling this code.482*/483AWT_LOCK();484if (isDisplayLocal(env)) {485x11dirs = getX11FontPath();486}487AWT_UNLOCK();488#if defined(__linux__)489}490#endif491}492#endif /* !HEADLESS */493path = mergePaths(fcdirs, x11dirs, knowndirs, noType1);494if (fcdirs != NULL) {495char **p = fcdirs;496while (*p != NULL) free(*p++);497free(fcdirs);498}499500if (x11dirs != NULL) {501char **p = x11dirs;502while (*p != NULL) free(*p++);503free(x11dirs);504}505506return path;507}508509JNIEXPORT jstring JNICALL Java_sun_awt_FcFontManager_getFontPathNative510(JNIEnv *env, jobject thiz, jboolean noType1, jboolean isX11) {511jstring ret;512static char *ptr = NULL; /* retain result across calls */513514if (ptr == NULL) {515ptr = getPlatformFontPathChars(env, noType1, isX11);516}517ret = (*env)->NewStringUTF(env, ptr);518return ret;519}520521#include <dlfcn.h>522523#include <fontconfig/fontconfig.h>524525526static void* openFontConfig() {527528char *homeEnv;529static char *homeEnvStr = "HOME="; /* must be static */530void* libfontconfig = NULL;531532/* Private workaround to not use fontconfig library.533* May be useful during testing/debugging534*/535char *useFC = getenv("USE_J2D_FONTCONFIG");536if (useFC != NULL && !strcmp(useFC, "no")) {537return NULL;538}539540#if defined(_AIX)541/* On AIX, fontconfig is not a standard package supported by IBM.542* instead it has to be installed from the "AIX Toolbox for Linux Applications"543* site http://www-03.ibm.com/systems/power/software/aix/linux/toolbox/alpha.html544* and will be installed under /opt/freeware/lib/libfontconfig.a.545* Notice that the archive contains the real 32- and 64-bit shared libraries.546* We first try to load 'libfontconfig.so' from the default library path in the547* case the user has installed a private version of the library and if that548* doesn't succeed, we try the version from /opt/freeware/lib/libfontconfig.a549*/550libfontconfig = dlopen("libfontconfig.so", RTLD_LOCAL|RTLD_LAZY);551if (libfontconfig == NULL) {552libfontconfig = dlopen("/opt/freeware/lib/libfontconfig.a(libfontconfig.so.1)", RTLD_MEMBER|RTLD_LOCAL|RTLD_LAZY);553if (libfontconfig == NULL) {554return NULL;555}556}557#else558/* 64 bit sparc should pick up the right version from the lib path.559* New features may be added to libfontconfig, this is expected to560* be compatible with old features, but we may need to start561* distinguishing the library version, to know whether to expect562* certain symbols - and functionality - to be available.563* Also add explicit search for .so.1 in case .so symlink doesn't exist.564*/565libfontconfig = dlopen(FONTCONFIG_DLL_VERSIONED, RTLD_LOCAL|RTLD_LAZY);566if (libfontconfig == NULL) {567libfontconfig = dlopen(FONTCONFIG_DLL, RTLD_LOCAL|RTLD_LAZY);568if (libfontconfig == NULL) {569return NULL;570}571}572#endif573574/* Version 1.0 of libfontconfig crashes if HOME isn't defined in575* the environment. This should generally never happen, but we can't576* control it, and can't control the version of fontconfig, so iff577* its not defined we set it to an empty value which is sufficient578* to prevent a crash. I considered unsetting it before exit, but579* it doesn't appear to work on Solaris, so I will leave it set.580*/581homeEnv = getenv("HOME");582if (homeEnv == NULL) {583putenv(homeEnvStr);584}585586return libfontconfig;587}588589typedef void* (FcFiniFuncType)();590591static void closeFontConfig(void* libfontconfig, jboolean fcFini) {592593/* NB FcFini is not in (eg) the Solaris 10 version of fontconfig. Its not594* clear if this means we are really leaking resources in those cases595* but it seems we should call this function when its available.596* But since the Swing GTK code may be still accessing the lib, its probably597* safest for now to just let this "leak" rather than potentially598* concurrently free global data still in use by other code.599*/600#if 0601if (fcFini) { /* release resources */602FcFiniFuncType FcFini = (FcFiniFuncType)dlsym(libfontconfig, "FcFini");603604if (FcFini != NULL) {605(*FcFini)();606}607}608#endif609dlclose(libfontconfig);610}611612typedef FcConfig* (*FcInitLoadConfigFuncType)();613typedef FcPattern* (*FcPatternBuildFuncType)(FcPattern *orig, ...);614typedef FcObjectSet* (*FcObjectSetFuncType)(const char *first, ...);615typedef FcFontSet* (*FcFontListFuncType)(FcConfig *config,616FcPattern *p,617FcObjectSet *os);618typedef FcResult (*FcPatternGetBoolFuncType)(const FcPattern *p,619const char *object,620int n,621FcBool *b);622typedef FcResult (*FcPatternGetIntegerFuncType)(const FcPattern *p,623const char *object,624int n,625int *i);626typedef FcResult (*FcPatternGetStringFuncType)(const FcPattern *p,627const char *object,628int n,629FcChar8 ** s);630typedef FcChar8* (*FcStrDirnameFuncType)(const FcChar8 *file);631typedef void (*FcPatternDestroyFuncType)(FcPattern *p);632typedef void (*FcFontSetDestroyFuncType)(FcFontSet *s);633typedef FcPattern* (*FcNameParseFuncType)(const FcChar8 *name);634typedef FcBool (*FcPatternAddStringFuncType)(FcPattern *p,635const char *object,636const FcChar8 *s);637typedef void (*FcDefaultSubstituteFuncType)(FcPattern *p);638typedef FcBool (*FcConfigSubstituteFuncType)(FcConfig *config,639FcPattern *p,640FcMatchKind kind);641typedef FcPattern* (*FcFontMatchFuncType)(FcConfig *config,642FcPattern *p,643FcResult *result);644typedef FcFontSet* (*FcFontSetCreateFuncType)();645typedef FcBool (*FcFontSetAddFuncType)(FcFontSet *s, FcPattern *font);646647typedef FcResult (*FcPatternGetCharSetFuncType)(FcPattern *p,648const char *object,649int n,650FcCharSet **c);651typedef FcFontSet* (*FcFontSortFuncType)(FcConfig *config,652FcPattern *p,653FcBool trim,654FcCharSet **csp,655FcResult *result);656typedef FcCharSet* (*FcCharSetUnionFuncType)(const FcCharSet *a,657const FcCharSet *b);658typedef FcChar32 (*FcCharSetSubtractCountFuncType)(const FcCharSet *a,659const FcCharSet *b);660661typedef int (*FcGetVersionFuncType)();662663typedef FcStrList* (*FcConfigGetCacheDirsFuncType)(FcConfig *config);664typedef FcChar8* (*FcStrListNextFuncType)(FcStrList *list);665typedef FcChar8* (*FcStrListDoneFuncType)(FcStrList *list);666667static char **getFontConfigLocations() {668669char **fontdirs;670int numdirs = 0;671FcInitLoadConfigFuncType FcInitLoadConfig;672FcPatternBuildFuncType FcPatternBuild;673FcObjectSetFuncType FcObjectSetBuild;674FcFontListFuncType FcFontList;675FcPatternGetStringFuncType FcPatternGetString;676FcStrDirnameFuncType FcStrDirname;677FcPatternDestroyFuncType FcPatternDestroy;678FcFontSetDestroyFuncType FcFontSetDestroy;679680FcConfig *fontconfig;681FcPattern *pattern;682FcObjectSet *objset;683FcFontSet *fontSet;684FcStrList *strList;685FcChar8 *str;686int i, f, found, len=0;687char **fontPath;688689void* libfontconfig = openFontConfig();690691if (libfontconfig == NULL) {692return NULL;693}694695FcPatternBuild =696(FcPatternBuildFuncType)dlsym(libfontconfig, "FcPatternBuild");697FcObjectSetBuild =698(FcObjectSetFuncType)dlsym(libfontconfig, "FcObjectSetBuild");699FcFontList =700(FcFontListFuncType)dlsym(libfontconfig, "FcFontList");701FcPatternGetString =702(FcPatternGetStringFuncType)dlsym(libfontconfig, "FcPatternGetString");703FcStrDirname =704(FcStrDirnameFuncType)dlsym(libfontconfig, "FcStrDirname");705FcPatternDestroy =706(FcPatternDestroyFuncType)dlsym(libfontconfig, "FcPatternDestroy");707FcFontSetDestroy =708(FcFontSetDestroyFuncType)dlsym(libfontconfig, "FcFontSetDestroy");709710if (FcPatternBuild == NULL ||711FcObjectSetBuild == NULL ||712FcPatternGetString == NULL ||713FcFontList == NULL ||714FcStrDirname == NULL ||715FcPatternDestroy == NULL ||716FcFontSetDestroy == NULL) { /* problem with the library: return. */717closeFontConfig(libfontconfig, JNI_FALSE);718return NULL;719}720721/* Make calls into the fontconfig library to build a search for722* outline fonts, and to get the set of full file paths from the matches.723* This set is returned from the call to FcFontList(..)724* We allocate an array of char* pointers sufficient to hold all725* the matches + 1 extra which ensures there will be a NULL after all726* valid entries.727* We call FcStrDirname strip the file name from the path, and728* check if we have yet seen this directory. If not we add a pointer to729* it into our array of char*. Note that FcStrDirname returns newly730* allocated storage so we can use this in the return char** value.731* Finally we clean up, freeing allocated resources, and return the732* array of unique directories.733*/734pattern = (*FcPatternBuild)(NULL, FC_OUTLINE, FcTypeBool, FcTrue, NULL);735objset = (*FcObjectSetBuild)(FC_FILE, NULL);736fontSet = (*FcFontList)(NULL, pattern, objset);737if (fontSet == NULL) {738/* FcFontList() may return NULL if fonts are not installed. */739fontdirs = NULL;740} else {741fontdirs = (char**)calloc(fontSet->nfont+1, sizeof(char*));742if (fontdirs == NULL) {743(*FcFontSetDestroy)(fontSet);744goto cleanup;745}746for (f=0; f < fontSet->nfont; f++) {747FcChar8 *file;748FcChar8 *dir;749if ((*FcPatternGetString)(fontSet->fonts[f], FC_FILE, 0, &file) ==750FcResultMatch) {751dir = (*FcStrDirname)(file);752found = 0;753for (i=0;i<numdirs; i++) {754if (strcmp(fontdirs[i], (char*)dir) == 0) {755found = 1;756break;757}758}759if (!found) {760fontdirs[numdirs++] = (char*)dir;761} else {762free((char*)dir);763}764}765}766/* Free fontset if one was returned */767(*FcFontSetDestroy)(fontSet);768}769770cleanup:771/* Free memory and close the ".so" */772(*FcPatternDestroy)(pattern);773closeFontConfig(libfontconfig, JNI_TRUE);774return fontdirs;775}776777/* These are copied from sun.awt.SunHints.778* Consider initialising them as ints using JNI for more robustness.779*/780#define TEXT_AA_OFF 1781#define TEXT_AA_ON 2782#define TEXT_AA_LCD_HRGB 4783#define TEXT_AA_LCD_HBGR 5784#define TEXT_AA_LCD_VRGB 6785#define TEXT_AA_LCD_VBGR 7786787JNIEXPORT jint JNICALL788Java_sun_font_FontConfigManager_getFontConfigAASettings789(JNIEnv *env, jclass obj, jstring localeStr, jstring fcNameStr) {790791FcNameParseFuncType FcNameParse;792FcPatternAddStringFuncType FcPatternAddString;793FcConfigSubstituteFuncType FcConfigSubstitute;794FcDefaultSubstituteFuncType FcDefaultSubstitute;795FcFontMatchFuncType FcFontMatch;796FcPatternGetBoolFuncType FcPatternGetBool;797FcPatternGetIntegerFuncType FcPatternGetInteger;798FcPatternDestroyFuncType FcPatternDestroy;799800FcPattern *pattern, *matchPattern;801FcResult result;802FcBool antialias = FcFalse;803int rgba = 0;804const char *locale=NULL, *fcName=NULL;805void* libfontconfig;806807if (fcNameStr == NULL || localeStr == NULL) {808return -1;809}810811fcName = (*env)->GetStringUTFChars(env, fcNameStr, 0);812if (fcName == NULL) {813return -1;814}815locale = (*env)->GetStringUTFChars(env, localeStr, 0);816817if ((libfontconfig = openFontConfig()) == NULL) {818(*env)->ReleaseStringUTFChars(env, fcNameStr, (const char*)fcName);819if (locale) {820(*env)->ReleaseStringUTFChars(env, localeStr,(const char*)locale);821}822return -1;823}824825FcNameParse = (FcNameParseFuncType)dlsym(libfontconfig, "FcNameParse");826FcPatternAddString =827(FcPatternAddStringFuncType)dlsym(libfontconfig, "FcPatternAddString");828FcConfigSubstitute =829(FcConfigSubstituteFuncType)dlsym(libfontconfig, "FcConfigSubstitute");830FcDefaultSubstitute = (FcDefaultSubstituteFuncType)831dlsym(libfontconfig, "FcDefaultSubstitute");832FcFontMatch = (FcFontMatchFuncType)dlsym(libfontconfig, "FcFontMatch");833FcPatternGetBool = (FcPatternGetBoolFuncType)834dlsym(libfontconfig, "FcPatternGetBool");835FcPatternGetInteger = (FcPatternGetIntegerFuncType)836dlsym(libfontconfig, "FcPatternGetInteger");837FcPatternDestroy =838(FcPatternDestroyFuncType)dlsym(libfontconfig, "FcPatternDestroy");839840if (FcNameParse == NULL ||841FcPatternAddString == NULL ||842FcConfigSubstitute == NULL ||843FcDefaultSubstitute == NULL ||844FcFontMatch == NULL ||845FcPatternGetBool == NULL ||846FcPatternGetInteger == NULL ||847FcPatternDestroy == NULL) { /* problem with the library: return. */848849(*env)->ReleaseStringUTFChars(env, fcNameStr, (const char*)fcName);850if (locale) {851(*env)->ReleaseStringUTFChars(env, localeStr,(const char*)locale);852}853closeFontConfig(libfontconfig, JNI_FALSE);854return -1;855}856857858pattern = (*FcNameParse)((FcChar8 *)fcName);859if (locale != NULL) {860(*FcPatternAddString)(pattern, FC_LANG, (unsigned char*)locale);861}862(*FcConfigSubstitute)(NULL, pattern, FcMatchPattern);863(*FcDefaultSubstitute)(pattern);864matchPattern = (*FcFontMatch)(NULL, pattern, &result);865/* Perhaps should call FcFontRenderPrepare() here as some pattern866* elements might change as a result of that call, but I'm not seeing867* any difference in testing.868*/869if (matchPattern) {870(*FcPatternGetBool)(matchPattern, FC_ANTIALIAS, 0, &antialias);871(*FcPatternGetInteger)(matchPattern, FC_RGBA, 0, &rgba);872(*FcPatternDestroy)(matchPattern);873}874(*FcPatternDestroy)(pattern);875876(*env)->ReleaseStringUTFChars(env, fcNameStr, (const char*)fcName);877if (locale) {878(*env)->ReleaseStringUTFChars(env, localeStr, (const char*)locale);879}880closeFontConfig(libfontconfig, JNI_TRUE);881882if (antialias == FcFalse) {883return TEXT_AA_OFF;884} else if (rgba <= FC_RGBA_UNKNOWN || rgba >= FC_RGBA_NONE) {885return TEXT_AA_ON;886} else {887switch (rgba) {888case FC_RGBA_RGB : return TEXT_AA_LCD_HRGB;889case FC_RGBA_BGR : return TEXT_AA_LCD_HBGR;890case FC_RGBA_VRGB : return TEXT_AA_LCD_VRGB;891case FC_RGBA_VBGR : return TEXT_AA_LCD_VBGR;892default : return TEXT_AA_LCD_HRGB; // should not get here.893}894}895}896897JNIEXPORT jint JNICALL898Java_sun_font_FontConfigManager_getFontConfigVersion899(JNIEnv *env, jclass obj) {900901void* libfontconfig;902FcGetVersionFuncType FcGetVersion;903int version = 0;904905if ((libfontconfig = openFontConfig()) == NULL) {906return 0;907}908909FcGetVersion = (FcGetVersionFuncType)dlsym(libfontconfig, "FcGetVersion");910911if (FcGetVersion == NULL) {912closeFontConfig(libfontconfig, JNI_FALSE);913return 0;914}915version = (*FcGetVersion)();916closeFontConfig(libfontconfig, JNI_FALSE);917918return version;919}920921922JNIEXPORT void JNICALL923Java_sun_font_FontConfigManager_getFontConfig924(JNIEnv *env, jclass obj, jstring localeStr, jobject fcInfoObj,925jobjectArray fcCompFontArray, jboolean includeFallbacks) {926927FcNameParseFuncType FcNameParse;928FcPatternAddStringFuncType FcPatternAddString;929FcConfigSubstituteFuncType FcConfigSubstitute;930FcDefaultSubstituteFuncType FcDefaultSubstitute;931FcFontMatchFuncType FcFontMatch;932FcPatternGetStringFuncType FcPatternGetString;933FcPatternDestroyFuncType FcPatternDestroy;934FcPatternGetCharSetFuncType FcPatternGetCharSet;935FcFontSortFuncType FcFontSort;936FcFontSetDestroyFuncType FcFontSetDestroy;937FcCharSetUnionFuncType FcCharSetUnion;938FcCharSetSubtractCountFuncType FcCharSetSubtractCount;939FcGetVersionFuncType FcGetVersion;940FcConfigGetCacheDirsFuncType FcConfigGetCacheDirs;941FcStrListNextFuncType FcStrListNext;942FcStrListDoneFuncType FcStrListDone;943944int i, arrlen;945jobject fcCompFontObj;946jstring fcNameStr, jstr;947const char *locale, *fcName;948FcPattern *pattern;949FcResult result;950void* libfontconfig;951jfieldID fcNameID, fcFirstFontID, fcAllFontsID, fcVersionID, fcCacheDirsID;952jfieldID familyNameID, styleNameID, fullNameID, fontFileID;953jmethodID fcFontCons;954char* debugMinGlyphsStr = getenv("J2D_DEBUG_MIN_GLYPHS");955jclass fcInfoClass;956jclass fcCompFontClass;957jclass fcFontClass;958959CHECK_NULL(fcInfoObj);960CHECK_NULL(fcCompFontArray);961962fcInfoClass =963(*env)->FindClass(env, "sun/font/FontConfigManager$FontConfigInfo");964CHECK_NULL(fcInfoClass);965fcCompFontClass =966(*env)->FindClass(env, "sun/font/FontConfigManager$FcCompFont");967CHECK_NULL(fcCompFontClass);968fcFontClass =969(*env)->FindClass(env, "sun/font/FontConfigManager$FontConfigFont");970CHECK_NULL(fcFontClass);971972973CHECK_NULL(fcVersionID = (*env)->GetFieldID(env, fcInfoClass, "fcVersion", "I"));974CHECK_NULL(fcCacheDirsID = (*env)->GetFieldID(env, fcInfoClass, "cacheDirs",975"[Ljava/lang/String;"));976CHECK_NULL(fcNameID = (*env)->GetFieldID(env, fcCompFontClass,977"fcName", "Ljava/lang/String;"));978CHECK_NULL(fcFirstFontID = (*env)->GetFieldID(env, fcCompFontClass, "firstFont",979"Lsun/font/FontConfigManager$FontConfigFont;"));980CHECK_NULL(fcAllFontsID = (*env)->GetFieldID(env, fcCompFontClass, "allFonts",981"[Lsun/font/FontConfigManager$FontConfigFont;"));982CHECK_NULL(fcFontCons = (*env)->GetMethodID(env, fcFontClass, "<init>", "()V"));983CHECK_NULL(familyNameID = (*env)->GetFieldID(env, fcFontClass,984"familyName", "Ljava/lang/String;"));985CHECK_NULL(styleNameID = (*env)->GetFieldID(env, fcFontClass,986"styleStr", "Ljava/lang/String;"));987CHECK_NULL(fullNameID = (*env)->GetFieldID(env, fcFontClass,988"fullName", "Ljava/lang/String;"));989CHECK_NULL(fontFileID = (*env)->GetFieldID(env, fcFontClass,990"fontFile", "Ljava/lang/String;"));991992if ((libfontconfig = openFontConfig()) == NULL) {993return;994}995996FcNameParse = (FcNameParseFuncType)dlsym(libfontconfig, "FcNameParse");997FcPatternAddString =998(FcPatternAddStringFuncType)dlsym(libfontconfig, "FcPatternAddString");999FcConfigSubstitute =1000(FcConfigSubstituteFuncType)dlsym(libfontconfig, "FcConfigSubstitute");1001FcDefaultSubstitute = (FcDefaultSubstituteFuncType)1002dlsym(libfontconfig, "FcDefaultSubstitute");1003FcFontMatch = (FcFontMatchFuncType)dlsym(libfontconfig, "FcFontMatch");1004FcPatternGetString =1005(FcPatternGetStringFuncType)dlsym(libfontconfig, "FcPatternGetString");1006FcPatternDestroy =1007(FcPatternDestroyFuncType)dlsym(libfontconfig, "FcPatternDestroy");1008FcPatternGetCharSet =1009(FcPatternGetCharSetFuncType)dlsym(libfontconfig,1010"FcPatternGetCharSet");1011FcFontSort =1012(FcFontSortFuncType)dlsym(libfontconfig, "FcFontSort");1013FcFontSetDestroy =1014(FcFontSetDestroyFuncType)dlsym(libfontconfig, "FcFontSetDestroy");1015FcCharSetUnion =1016(FcCharSetUnionFuncType)dlsym(libfontconfig, "FcCharSetUnion");1017FcCharSetSubtractCount =1018(FcCharSetSubtractCountFuncType)dlsym(libfontconfig,1019"FcCharSetSubtractCount");1020FcGetVersion = (FcGetVersionFuncType)dlsym(libfontconfig, "FcGetVersion");10211022if (FcNameParse == NULL ||1023FcPatternAddString == NULL ||1024FcConfigSubstitute == NULL ||1025FcDefaultSubstitute == NULL ||1026FcFontMatch == NULL ||1027FcPatternGetString == NULL ||1028FcPatternDestroy == NULL ||1029FcPatternGetCharSet == NULL ||1030FcFontSetDestroy == NULL ||1031FcCharSetUnion == NULL ||1032FcGetVersion == NULL ||1033FcCharSetSubtractCount == NULL) {/* problem with the library: return.*/1034closeFontConfig(libfontconfig, JNI_FALSE);1035return;1036}10371038(*env)->SetIntField(env, fcInfoObj, fcVersionID, (*FcGetVersion)());10391040/* Optionally get the cache dir locations. This isn't1041* available until v 2.4.x, but this is OK since on those later versions1042* we can check the time stamps on the cache dirs to see if we1043* are out of date. There are a couple of assumptions here. First1044* that the time stamp on the directory changes when the contents are1045* updated. Secondly that the locations don't change. The latter is1046* most likely if a new version of fontconfig is installed, but we also1047* invalidate the cache if we detect that. Arguably even that is "rare",1048* and most likely is tied to an OS upgrade which gets a new file anyway.1049*/1050FcConfigGetCacheDirs =1051(FcConfigGetCacheDirsFuncType)dlsym(libfontconfig,1052"FcConfigGetCacheDirs");1053FcStrListNext =1054(FcStrListNextFuncType)dlsym(libfontconfig, "FcStrListNext");1055FcStrListDone =1056(FcStrListDoneFuncType)dlsym(libfontconfig, "FcStrListDone");1057if (FcStrListNext != NULL && FcStrListDone != NULL &&1058FcConfigGetCacheDirs != NULL) {10591060FcStrList* cacheDirs;1061FcChar8* cacheDir;1062int cnt = 0;1063jobject cacheDirArray =1064(*env)->GetObjectField(env, fcInfoObj, fcCacheDirsID);1065int max = (*env)->GetArrayLength(env, cacheDirArray);10661067cacheDirs = (*FcConfigGetCacheDirs)(NULL);1068if (cacheDirs != NULL) {1069while ((cnt < max) && (cacheDir = (*FcStrListNext)(cacheDirs))) {1070jstr = (*env)->NewStringUTF(env, (const char*)cacheDir);1071JNU_CHECK_EXCEPTION(env);10721073(*env)->SetObjectArrayElement(env, cacheDirArray, cnt++, jstr);1074(*env)->DeleteLocalRef(env, jstr);1075}1076(*FcStrListDone)(cacheDirs);1077}1078}10791080locale = (*env)->GetStringUTFChars(env, localeStr, 0);1081if (locale == NULL) {1082(*env)->ExceptionClear(env);1083JNU_ThrowOutOfMemoryError(env, "Could not create locale");1084return;1085}10861087arrlen = (*env)->GetArrayLength(env, fcCompFontArray);1088for (i=0; i<arrlen; i++) {1089FcFontSet* fontset;1090int fn, j, fontCount, nfonts;1091unsigned int minGlyphs;1092FcChar8 **family, **styleStr, **fullname, **file;1093jarray fcFontArr = NULL;1094FcCharSet *unionCharset = NULL;10951096fcCompFontObj = (*env)->GetObjectArrayElement(env, fcCompFontArray, i);1097fcNameStr =1098(jstring)((*env)->GetObjectField(env, fcCompFontObj, fcNameID));1099fcName = (*env)->GetStringUTFChars(env, fcNameStr, 0);1100if (fcName == NULL) {1101(*env)->DeleteLocalRef(env, fcCompFontObj);1102(*env)->DeleteLocalRef(env, fcNameStr);1103continue;1104}1105pattern = (*FcNameParse)((FcChar8 *)fcName);1106(*env)->ReleaseStringUTFChars(env, fcNameStr, (const char*)fcName);1107(*env)->DeleteLocalRef(env, fcNameStr);1108if (pattern == NULL) {1109closeFontConfig(libfontconfig, JNI_FALSE);1110if (locale) {1111(*env)->ReleaseStringUTFChars(env, localeStr, (const char*)locale);1112}1113return;1114}11151116/* locale may not usually be necessary as fontconfig appears to apply1117* this anyway based on the user's environment. However we want1118* to use the value of the JDK startup locale so this should take1119* care of it.1120*/1121if (locale != NULL) {1122(*FcPatternAddString)(pattern, FC_LANG, (unsigned char*)locale);1123}1124(*FcConfigSubstitute)(NULL, pattern, FcMatchPattern);1125(*FcDefaultSubstitute)(pattern);1126fontset = (*FcFontSort)(NULL, pattern, FcTrue, NULL, &result);1127if (fontset == NULL) {1128(*FcPatternDestroy)(pattern);1129closeFontConfig(libfontconfig, JNI_FALSE);1130if (locale) {1131(*env)->ReleaseStringUTFChars(env, localeStr, (const char*)locale);1132}1133return;1134}11351136/* fontconfig returned us "nfonts". If we are just getting the1137* first font, we set nfont to zero. Otherwise we use "nfonts".1138* Next create separate C arrrays of length nfonts for family file etc.1139* Inspect the returned fonts and the ones we like (adds enough glyphs)1140* are added to the arrays and we increment 'fontCount'.1141*/1142nfonts = fontset->nfont;1143family = (FcChar8**)calloc(nfonts, sizeof(FcChar8*));1144styleStr = (FcChar8**)calloc(nfonts, sizeof(FcChar8*));1145fullname = (FcChar8**)calloc(nfonts, sizeof(FcChar8*));1146file = (FcChar8**)calloc(nfonts, sizeof(FcChar8*));1147if (family == NULL || styleStr == NULL ||1148fullname == NULL || file == NULL) {1149if (family != NULL) {1150free(family);1151}1152if (styleStr != NULL) {1153free(styleStr);1154}1155if (fullname != NULL) {1156free(fullname);1157}1158if (file != NULL) {1159free(file);1160}1161(*FcPatternDestroy)(pattern);1162(*FcFontSetDestroy)(fontset);1163closeFontConfig(libfontconfig, JNI_FALSE);1164if (locale) {1165(*env)->ReleaseStringUTFChars(env, localeStr, (const char*)locale);1166}1167return;1168}1169fontCount = 0;1170minGlyphs = 20;1171if (debugMinGlyphsStr != NULL) {1172int val = minGlyphs;1173sscanf(debugMinGlyphsStr, "%5d", &val);1174if (val >= 0 && val <= 65536) {1175minGlyphs = val;1176}1177}11781179for (j=0; j<nfonts; j++) {1180FcPattern *fontPattern = fontset->fonts[j];1181FcChar8 *fontformat;1182FcCharSet *charset = NULL;11831184fontformat = NULL;1185(*FcPatternGetString)(fontPattern, FC_FONTFORMAT, 0, &fontformat);1186/* We only want TrueType fonts but some Linuxes still depend1187* on Type 1 fonts for some Locale support, so we'll allow1188* them there.1189*/1190if (fontformat != NULL1191&& (strcmp((char*)fontformat, "TrueType") != 0)1192#if defined(__linux__) || defined(_AIX)1193&& (strcmp((char*)fontformat, "Type 1") != 0)1194&& (strcmp((char*)fontformat, "CFF") != 0)1195#endif1196) {1197continue;1198}1199result = (*FcPatternGetCharSet)(fontPattern,1200FC_CHARSET, 0, &charset);1201if (result != FcResultMatch) {1202free(family);1203free(fullname);1204free(styleStr);1205free(file);1206(*FcPatternDestroy)(pattern);1207(*FcFontSetDestroy)(fontset);1208closeFontConfig(libfontconfig, JNI_FALSE);1209if (locale) {1210(*env)->ReleaseStringUTFChars(env, localeStr, (const char*)locale);1211}1212return;1213}12141215/* We don't want 20 or 30 fonts, so once we hit 10 fonts,1216* then require that they really be adding value. Too many1217* adversely affects load time for minimal value-add.1218* This is still likely far more than we've had in the past.1219*/1220if (j==10) {1221minGlyphs = 50;1222}1223if (unionCharset == NULL) {1224unionCharset = charset;1225} else {1226if ((*FcCharSetSubtractCount)(charset, unionCharset)1227> minGlyphs) {1228unionCharset = (* FcCharSetUnion)(unionCharset, charset);1229} else {1230continue;1231}1232}12331234fontCount++; // found a font we will use.1235(*FcPatternGetString)(fontPattern, FC_FILE, 0, &file[j]);1236(*FcPatternGetString)(fontPattern, FC_FAMILY, 0, &family[j]);1237(*FcPatternGetString)(fontPattern, FC_STYLE, 0, &styleStr[j]);1238(*FcPatternGetString)(fontPattern, FC_FULLNAME, 0, &fullname[j]);1239if (!includeFallbacks) {1240break;1241}1242if (fontCount == 254) {1243break; // CompositeFont will only use up to 254 slots from here.1244}1245}12461247/* Once we get here 'fontCount' is the number of returned fonts1248* we actually want to use, so we create 'fcFontArr' of that length.1249* The non-null entries of "family[]" etc are those fonts.1250* Then loop again over all nfonts adding just those non-null ones1251* to 'fcFontArr'. If its null (we didn't want the font)1252* then we don't enter the main body.1253* So we should never get more than 'fontCount' entries.1254*/1255if (includeFallbacks) {1256fcFontArr =1257(*env)->NewObjectArray(env, fontCount, fcFontClass, NULL);1258if (IS_NULL(fcFontArr)) {1259free(family);1260free(fullname);1261free(styleStr);1262free(file);1263(*FcPatternDestroy)(pattern);1264(*FcFontSetDestroy)(fontset);1265closeFontConfig(libfontconfig, JNI_FALSE);1266if (locale) {1267(*env)->ReleaseStringUTFChars(env, localeStr, (const char*)locale);1268}1269return;1270}1271(*env)->SetObjectField(env,fcCompFontObj, fcAllFontsID, fcFontArr);1272}1273fn=0;12741275for (j=0;j<nfonts;j++) {1276if (family[j] != NULL) {1277jobject fcFont =1278(*env)->NewObject(env, fcFontClass, fcFontCons);1279if (IS_NULL(fcFont)) break;1280jstr = (*env)->NewStringUTF(env, (const char*)family[j]);1281if (IS_NULL(jstr)) break;1282(*env)->SetObjectField(env, fcFont, familyNameID, jstr);1283(*env)->DeleteLocalRef(env, jstr);1284if (file[j] != NULL) {1285jstr = (*env)->NewStringUTF(env, (const char*)file[j]);1286if (IS_NULL(jstr)) break;1287(*env)->SetObjectField(env, fcFont, fontFileID, jstr);1288(*env)->DeleteLocalRef(env, jstr);1289}1290if (styleStr[j] != NULL) {1291jstr = (*env)->NewStringUTF(env, (const char*)styleStr[j]);1292if (IS_NULL(jstr)) break;1293(*env)->SetObjectField(env, fcFont, styleNameID, jstr);1294(*env)->DeleteLocalRef(env, jstr);1295}1296if (fullname[j] != NULL) {1297jstr = (*env)->NewStringUTF(env, (const char*)fullname[j]);1298if (IS_NULL(jstr)) break;1299(*env)->SetObjectField(env, fcFont, fullNameID, jstr);1300(*env)->DeleteLocalRef(env, jstr);1301}1302if (fn==0) {1303(*env)->SetObjectField(env, fcCompFontObj,1304fcFirstFontID, fcFont);1305}1306if (includeFallbacks) {1307(*env)->SetObjectArrayElement(env, fcFontArr, fn++,fcFont);1308} else {1309(*env)->DeleteLocalRef(env, fcFont);1310break;1311}1312(*env)->DeleteLocalRef(env, fcFont);1313}1314}1315if (includeFallbacks) {1316(*env)->DeleteLocalRef(env, fcFontArr);1317}1318(*env)->DeleteLocalRef(env, fcCompFontObj);1319(*FcFontSetDestroy)(fontset);1320(*FcPatternDestroy)(pattern);1321free(family);1322free(styleStr);1323free(fullname);1324free(file);1325}13261327/* release resources and close the ".so" */13281329if (locale) {1330(*env)->ReleaseStringUTFChars(env, localeStr, (const char*)locale);1331}1332closeFontConfig(libfontconfig, JNI_TRUE);1333}133413351336