Path: blob/jdk8u272-b10-aarch32-20201026/jdk/src/solaris/native/sun/awt/fontpath.c
48789 views
/*1* Copyright (c) 1998, 2016, 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>36#ifdef __solaris__37#include <sys/systeminfo.h>38#endif3940#include <jni.h>41#include <jni_util.h>42#include <jvm_md.h>43#include <sizecalc.h>44#ifndef HEADLESS45#include <X11/Xlib.h>46#include <awt.h>47#else48/* locks ought to be included from awt.h */49#define AWT_LOCK()50#define AWT_UNLOCK()51#endif /* !HEADLESS */5253#if defined(__linux__) && !defined(MAP_FAILED)54#define MAP_FAILED ((caddr_t)-1)55#endif5657#ifndef HEADLESS58extern Display *awt_display;59#endif /* !HEADLESS */6061#define FONTCONFIG_DLL_VERSIONED VERSIONED_JNI_LIB_NAME("fontconfig", "1")62#define FONTCONFIG_DLL JNI_LIB_NAME("fontconfig")6364#define MAXFDIRS 512 /* Max number of directories that contain fonts */6566#if defined(__solaris__)67/*68* This can be set in the makefile to "/usr/X11" if so desired.69*/70#ifndef OPENWINHOMELIB71#define OPENWINHOMELIB "/usr/openwin/lib/"72#endif7374/* This is all known Solaris X11 directories on Solaris 8, 9 and 10.75* It is ordered to give precedence to TrueType directories.76* It is needed if fontconfig is not installed or configured properly.77*/78static char *fullSolarisFontPath[] = {79OPENWINHOMELIB "X11/fonts/TrueType",80OPENWINHOMELIB "locale/euro_fonts/X11/fonts/TrueType",81OPENWINHOMELIB "locale/iso_8859_2/X11/fonts/TrueType",82OPENWINHOMELIB "locale/iso_8859_5/X11/fonts/TrueType",83OPENWINHOMELIB "locale/iso_8859_7/X11/fonts/TrueType",84OPENWINHOMELIB "locale/iso_8859_8/X11/fonts/TrueType",85OPENWINHOMELIB "locale/iso_8859_9/X11/fonts/TrueType",86OPENWINHOMELIB "locale/iso_8859_13/X11/fonts/TrueType",87OPENWINHOMELIB "locale/iso_8859_15/X11/fonts/TrueType",88OPENWINHOMELIB "locale/ar/X11/fonts/TrueType",89OPENWINHOMELIB "locale/hi_IN.UTF-8/X11/fonts/TrueType",90OPENWINHOMELIB "locale/ja/X11/fonts/TT",91OPENWINHOMELIB "locale/ko/X11/fonts/TrueType",92OPENWINHOMELIB "locale/ko.UTF-8/X11/fonts/TrueType",93OPENWINHOMELIB "locale/KOI8-R/X11/fonts/TrueType",94OPENWINHOMELIB "locale/ru.ansi-1251/X11/fonts/TrueType",95OPENWINHOMELIB "locale/th_TH/X11/fonts/TrueType",96OPENWINHOMELIB "locale/zh_TW/X11/fonts/TrueType",97OPENWINHOMELIB "locale/zh_TW.BIG5/X11/fonts/TT",98OPENWINHOMELIB "locale/zh_HK.BIG5HK/X11/fonts/TT",99OPENWINHOMELIB "locale/zh_CN.GB18030/X11/fonts/TrueType",100OPENWINHOMELIB "locale/zh/X11/fonts/TrueType",101OPENWINHOMELIB "locale/zh.GBK/X11/fonts/TrueType",102OPENWINHOMELIB "X11/fonts/Type1",103OPENWINHOMELIB "X11/fonts/Type1/sun",104OPENWINHOMELIB "X11/fonts/Type1/sun/outline",105OPENWINHOMELIB "locale/iso_8859_2/X11/fonts/Type1",106OPENWINHOMELIB "locale/iso_8859_4/X11/fonts/Type1",107OPENWINHOMELIB "locale/iso_8859_5/X11/fonts/Type1",108OPENWINHOMELIB "locale/iso_8859_7/X11/fonts/Type1",109OPENWINHOMELIB "locale/iso_8859_8/X11/fonts/Type1",110OPENWINHOMELIB "locale/iso_8859_9/X11/fonts/Type1",111OPENWINHOMELIB "locale/iso_8859_13/X11/fonts/Type1",112OPENWINHOMELIB "locale/ar/X11/fonts/Type1",113NULL, /* terminates the list */114};115116#elif defined( __linux__)117/* All the known interesting locations we have discovered on118* various flavors of Linux119*/120static char *fullLinuxFontPath[] = {121"/usr/X11R6/lib/X11/fonts/TrueType", /* RH 7.1+ */122"/usr/X11R6/lib/X11/fonts/truetype", /* SuSE */123"/usr/X11R6/lib/X11/fonts/tt",124"/usr/X11R6/lib/X11/fonts/TTF",125"/usr/X11R6/lib/X11/fonts/OTF", /* RH 9.0 (but empty!) */126"/usr/share/fonts/ja/TrueType", /* RH 7.2+ */127"/usr/share/fonts/truetype",128"/usr/share/fonts/ko/TrueType", /* RH 9.0 */129"/usr/share/fonts/zh_CN/TrueType", /* RH 9.0 */130"/usr/share/fonts/zh_TW/TrueType", /* RH 9.0 */131"/var/lib/defoma/x-ttcidfont-conf.d/dirs/TrueType", /* Debian */132"/usr/X11R6/lib/X11/fonts/Type1",133"/usr/share/fonts/default/Type1", /* RH 9.0 */134NULL, /* terminates the list */135};136#elif defined(_AIX)137static char *fullAixFontPath[] = {138"/usr/lpp/X11/lib/X11/fonts/Type1", /* from X11.fnt.iso_T1 */139"/usr/lpp/X11/lib/X11/fonts/TrueType", /* from X11.fnt.ucs.ttf */140NULL, /* terminates the list */141};142#endif143144static char **getFontConfigLocations();145146typedef struct {147const char *name[MAXFDIRS];148int num;149} fDirRecord, *fDirRecordPtr;150151#ifndef HEADLESS152153/*154* Returns True if display is local, False of it's remote.155*/156jboolean isDisplayLocal(JNIEnv *env) {157static jboolean isLocal = False;158static jboolean isLocalSet = False;159jboolean ret;160161if (! isLocalSet) {162jclass geCls = (*env)->FindClass(env, "java/awt/GraphicsEnvironment");163CHECK_NULL_RETURN(geCls, JNI_FALSE);164jmethodID getLocalGE = (*env)->GetStaticMethodID(env, geCls,165"getLocalGraphicsEnvironment",166"()Ljava/awt/GraphicsEnvironment;");167CHECK_NULL_RETURN(getLocalGE, JNI_FALSE);168jobject ge = (*env)->CallStaticObjectMethod(env, geCls, getLocalGE);169JNU_CHECK_EXCEPTION_RETURN(env, JNI_FALSE);170171jclass sgeCls = (*env)->FindClass(env,172"sun/java2d/SunGraphicsEnvironment");173CHECK_NULL_RETURN(sgeCls, JNI_FALSE);174if ((*env)->IsInstanceOf(env, ge, sgeCls)) {175jmethodID isDisplayLocal = (*env)->GetMethodID(env, sgeCls,176"isDisplayLocal",177"()Z");178JNU_CHECK_EXCEPTION_RETURN(env, JNI_FALSE);179isLocal = (*env)->CallBooleanMethod(env, ge, isDisplayLocal);180} else {181isLocal = True;182}183isLocalSet = True;184}185186return isLocal;187}188189static void AddFontsToX11FontPath ( fDirRecord *fDirP )190{191char *onePath;192int index, nPaths;193int origNumPaths, length;194int origIndex;195int totalDirCount;196char **origFontPath;197char **tempFontPath;198int doNotAppend;199int *appendDirList;200char **newFontPath;201int err, compareLength;202char fontDirPath[512];203int dirFile;204205doNotAppend = 0;206207if ( fDirP->num == 0 ) return;208209appendDirList = SAFE_SIZE_ARRAY_ALLOC(malloc, fDirP->num, sizeof ( int ));210if ( appendDirList == NULL ) {211return; /* if it fails we cannot do much */212}213214origFontPath = XGetFontPath ( awt_display, &nPaths );215216totalDirCount = nPaths;217origNumPaths = nPaths;218tempFontPath = origFontPath;219220221for (index = 0; index < fDirP->num; index++ ) {222223doNotAppend = 0;224225tempFontPath = origFontPath;226for ( origIndex = 0; origIndex < nPaths; origIndex++ ) {227228onePath = *tempFontPath;229230compareLength = strlen ( onePath );231if ( onePath[compareLength -1] == '/' )232compareLength--;233234/* there is a slash at the end of every solaris X11 font path name */235if ( strncmp ( onePath, fDirP->name[index], compareLength ) == 0 ) {236doNotAppend = 1;237break;238}239tempFontPath++;240}241242appendDirList[index] = 0;243if ( doNotAppend == 0 ) {244strcpy ( fontDirPath, fDirP->name[index] );245strcat ( fontDirPath, "/fonts.dir" );246dirFile = open ( fontDirPath, O_RDONLY, 0 );247if ( dirFile == -1 ) {248doNotAppend = 1;249} else {250close ( dirFile );251totalDirCount++;252appendDirList[index] = 1;253}254}255256}257258/* if no changes are required do not bother to do a setfontpath */259if ( totalDirCount == nPaths ) {260free ( ( void *) appendDirList );261XFreeFontPath ( origFontPath );262return;263}264265266newFontPath = SAFE_SIZE_ARRAY_ALLOC(malloc, totalDirCount, sizeof ( char **) );267/* if it fails free things and get out */268if ( newFontPath == NULL ) {269free ( ( void *) appendDirList );270XFreeFontPath ( origFontPath );271return;272}273274for ( origIndex = 0; origIndex < nPaths; origIndex++ ) {275onePath = origFontPath[origIndex];276newFontPath[origIndex] = onePath;277}278279/* now add the other font paths */280281for (index = 0; index < fDirP->num; index++ ) {282283if ( appendDirList[index] == 1 ) {284285/* printf ( "Appending %s\n", fDirP->name[index] ); */286287onePath = SAFE_SIZE_ARRAY_ALLOC(malloc, strlen (fDirP->name[index]) + 2, sizeof( char ) );288if (onePath == NULL) {289free ( ( void *) appendDirList );290XFreeFontPath ( origFontPath );291return;292}293strcpy ( onePath, fDirP->name[index] );294strcat ( onePath, "/" );295newFontPath[nPaths++] = onePath;296/* printf ( "The path to be appended is %s\n", onePath ); */297}298}299300/* printf ( "The dir count = %d\n", totalDirCount ); */301free ( ( void *) appendDirList );302303XSetFontPath ( awt_display, newFontPath, totalDirCount );304305for ( index = origNumPaths; index < totalDirCount; index++ ) {306free( newFontPath[index] );307}308309free ( (void *) newFontPath );310XFreeFontPath ( origFontPath );311return;312}313#endif /* !HEADLESS */314315316#ifndef HEADLESS317static char **getX11FontPath ()318{319char **x11Path, **fontdirs;320int i, pos, slen, nPaths, numDirs;321322x11Path = XGetFontPath (awt_display, &nPaths);323324/* This isn't ever going to be perfect: the font path may contain325* much we aren't interested in, but the cost should be moderate326* Exclude all directories that contain the strings "Speedo","/F3/",327* "75dpi", "100dpi", "misc" or "bitmap", or don't begin with a "/",328* the last of which should exclude font servers.329* Also exclude the user specific ".gnome*" directories which330* aren't going to contain the system fonts we need.331* Hopefully we are left only with Type1 and TrueType directories.332* It doesn't matter much if there are extraneous directories, it'll just333* cost us a little wasted effort upstream.334*/335fontdirs = (char**)calloc(nPaths+1, sizeof(char*));336pos = 0;337for (i=0; i < nPaths; i++) {338if (x11Path[i][0] != '/') {339continue;340}341if (strstr(x11Path[i], "/75dpi") != NULL) {342continue;343}344if (strstr(x11Path[i], "/100dpi") != NULL) {345continue;346}347if (strstr(x11Path[i], "/misc") != NULL) {348continue;349}350if (strstr(x11Path[i], "/Speedo") != NULL) {351continue;352}353if (strstr(x11Path[i], ".gnome") != NULL) {354continue;355}356#ifdef __solaris__357if (strstr(x11Path[i], "/F3/") != NULL) {358continue;359}360if (strstr(x11Path[i], "bitmap") != NULL) {361continue;362}363#endif364fontdirs[pos] = strdup(x11Path[i]);365slen = strlen(fontdirs[pos]);366if (slen > 0 && fontdirs[pos][slen-1] == '/') {367fontdirs[pos][slen-1] = '\0'; /* null out trailing "/" */368}369pos++;370}371372XFreeFontPath(x11Path);373if (pos == 0) {374free(fontdirs);375fontdirs = NULL;376}377return fontdirs;378}379380381#endif /* !HEADLESS */382383#if defined(__linux__)384/* from awt_LoadLibrary.c */385JNIEXPORT jboolean JNICALL AWTIsHeadless();386#endif387388/* This eliminates duplicates, at a non-linear but acceptable cost389* since the lists are expected to be reasonably short, and then390* deletes references to non-existent directories, and returns391* a single path consisting of unique font directories.392*/393static char* mergePaths(char **p1, char **p2, char **p3, jboolean noType1) {394395int len1=0, len2=0, len3=0, totalLen=0, numDirs=0,396currLen, i, j, found, pathLen=0;397char **ptr, **fontdirs;398char *fontPath = NULL;399400if (p1 != NULL) {401ptr = p1;402while (*ptr++ != NULL) len1++;403}404if (p2 != NULL) {405ptr = p2;406407while (*ptr++ != NULL) len2++;408}409if (p3 != NULL) {410ptr = p3;411while (*ptr++ != NULL) len3++;412}413totalLen = len1+len2+len3;414fontdirs = (char**)calloc(totalLen, sizeof(char*));415416for (i=0; i < len1; i++) {417if (noType1 && strstr(p1[i], "Type1") != NULL) {418continue;419}420fontdirs[numDirs++] = p1[i];421}422423currLen = numDirs; /* only compare against previous path dirs */424for (i=0; i < len2; i++) {425if (noType1 && strstr(p2[i], "Type1") != NULL) {426continue;427}428found = 0;429for (j=0; j < currLen; j++) {430if (strcmp(fontdirs[j], p2[i]) == 0) {431found = 1;432break;433}434}435if (!found) {436fontdirs[numDirs++] = p2[i];437}438}439440currLen = numDirs; /* only compare against previous path dirs */441for (i=0; i < len3; i++) {442if (noType1 && strstr(p3[i], "Type1") != NULL) {443continue;444}445found = 0;446for (j=0; j < currLen; j++) {447if (strcmp(fontdirs[j], p3[i]) == 0) {448found = 1;449break;450}451}452if (!found) {453fontdirs[numDirs++] = p3[i];454}455}456457/* Now fontdirs contains unique dirs and numDirs records how many.458* What we don't know is if they all exist. On reflection I think459* this isn't an issue, so for now I will return all these locations,460* converted to one string */461for (i=0; i<numDirs; i++) {462pathLen += (strlen(fontdirs[i]) + 1);463}464if (pathLen > 0 && (fontPath = malloc(pathLen))) {465*fontPath = '\0';466for (i = 0; i<numDirs; i++) {467if (i != 0) {468strcat(fontPath, ":");469}470strcat(fontPath, fontdirs[i]);471}472}473free (fontdirs);474475return fontPath;476}477478/*479* The goal of this function is to find all "system" fonts which480* are needed by the JRE to display text in supported locales etc, and481* to support APIs which allow users to enumerate all system fonts and use482* them from their Java applications.483* The preferred mechanism is now using the new "fontconfig" library484* This exists on newer versions of Linux and Solaris (S10 and above)485* The library is dynamically located. The results are merged with486* a set of "known" locations and with the X11 font path, if running in487* a local X11 environment.488* The hardwired paths are built into the JDK binary so as new font locations489* are created on a host plaform for them to be located by the JRE they will490* need to be added ito the host's font configuration database, typically491* /etc/fonts/local.conf, and to ensure that directory contains a fonts.dir492* NB: Fontconfig also depends heavily for performance on the host O/S493* maintaining up to date caches.494* This is consistent with the requirements of the desktop environments495* on these OSes.496* This also frees us from X11 APIs as JRE is required to function in497* a "headless" mode where there is no Xserver.498*/499static char *getPlatformFontPathChars(JNIEnv *env, jboolean noType1, jboolean isX11) {500501char **fcdirs = NULL, **x11dirs = NULL, **knowndirs = NULL, *path = NULL;502503/* As of 1.5 we try to use fontconfig on both Solaris and Linux.504* If its not available NULL is returned.505*/506fcdirs = getFontConfigLocations();507508#if defined(__linux__)509knowndirs = fullLinuxFontPath;510#elif defined(__solaris__)511knowndirs = fullSolarisFontPath;512#elif defined(_AIX)513knowndirs = fullAixFontPath;514#endif515/* REMIND: this code requires to be executed when the GraphicsEnvironment516* is already initialised. That is always true, but if it were not so,517* this code could throw an exception and the fontpath would fail to518* be initialised.519*/520#ifndef HEADLESS521if (isX11) { // The following only works in an x11 environment.522#if defined(__linux__)523/* There's no headless build on linux ... */524if (!AWTIsHeadless()) { /* .. so need to call a function to check */525#endif526/* Using the X11 font path to locate font files is now a fallback527* useful only if fontconfig failed, or is incomplete. So we could528* remove this code completely and the consequences should be rare529* and non-fatal. If this happens, then the calling Java code can530* be modified to no longer require that the AWT lock (the X11GE)531* be initialised prior to calling this code.532*/533AWT_LOCK();534if (isDisplayLocal(env)) {535x11dirs = getX11FontPath();536}537AWT_UNLOCK();538#if defined(__linux__)539}540#endif541}542#endif /* !HEADLESS */543path = mergePaths(fcdirs, x11dirs, knowndirs, noType1);544if (fcdirs != NULL) {545char **p = fcdirs;546while (*p != NULL) free(*p++);547free(fcdirs);548}549550if (x11dirs != NULL) {551char **p = x11dirs;552while (*p != NULL) free(*p++);553free(x11dirs);554}555556return path;557}558559JNIEXPORT jstring JNICALL Java_sun_awt_FcFontManager_getFontPathNative560(JNIEnv *env, jobject thiz, jboolean noType1, jboolean isX11) {561jstring ret;562static char *ptr = NULL; /* retain result across calls */563564if (ptr == NULL) {565ptr = getPlatformFontPathChars(env, noType1, isX11);566}567ret = (*env)->NewStringUTF(env, ptr);568return ret;569}570571#include <dlfcn.h>572573#include <fontconfig/fontconfig.h>574575576static void* openFontConfig() {577578char *homeEnv;579static char *homeEnvStr = "HOME="; /* must be static */580void* libfontconfig = NULL;581#ifdef __solaris__582#define SYSINFOBUFSZ 8583char sysinfobuf[SYSINFOBUFSZ];584#endif585586/* Private workaround to not use fontconfig library.587* May be useful during testing/debugging588*/589char *useFC = getenv("USE_J2D_FONTCONFIG");590if (useFC != NULL && !strcmp(useFC, "no")) {591return NULL;592}593594#ifdef __solaris__595/* fontconfig is likely not properly configured on S8/S9 - skip it,596* although allow user to override this behaviour with an env. variable597* ie if USE_J2D_FONTCONFIG=yes then we skip this test.598* NB "4" is the length of a string which matches our patterns.599*/600if (useFC == NULL || strcmp(useFC, "yes")) {601if (sysinfo(SI_RELEASE, sysinfobuf, SYSINFOBUFSZ) == 4) {602if ((!strcmp(sysinfobuf, "5.8") || !strcmp(sysinfobuf, "5.9"))) {603return NULL;604}605}606}607#endif608609#if defined(_AIX)610/* On AIX, fontconfig is not a standard package supported by IBM.611* instead it has to be installed from the "AIX Toolbox for Linux Applications"612* site http://www-03.ibm.com/systems/power/software/aix/linux/toolbox/alpha.html613* and will be installed under /opt/freeware/lib/libfontconfig.a.614* Notice that the archive contains the real 32- and 64-bit shared libraries.615* We first try to load 'libfontconfig.so' from the default library path in the616* case the user has installed a private version of the library and if that617* doesn't succeed, we try the version from /opt/freeware/lib/libfontconfig.a618*/619libfontconfig = dlopen("libfontconfig.so", RTLD_LOCAL|RTLD_LAZY);620if (libfontconfig == NULL) {621libfontconfig = dlopen("/opt/freeware/lib/libfontconfig.a(libfontconfig.so.1)", RTLD_MEMBER|RTLD_LOCAL|RTLD_LAZY);622if (libfontconfig == NULL) {623return NULL;624}625}626#else627/* 64 bit sparc should pick up the right version from the lib path.628* New features may be added to libfontconfig, this is expected to629* be compatible with old features, but we may need to start630* distinguishing the library version, to know whether to expect631* certain symbols - and functionality - to be available.632* Also add explicit search for .so.1 in case .so symlink doesn't exist.633*/634libfontconfig = dlopen(FONTCONFIG_DLL_VERSIONED, RTLD_LOCAL|RTLD_LAZY);635if (libfontconfig == NULL) {636libfontconfig = dlopen(FONTCONFIG_DLL, RTLD_LOCAL|RTLD_LAZY);637if (libfontconfig == NULL) {638return NULL;639}640}641#endif642643/* Version 1.0 of libfontconfig crashes if HOME isn't defined in644* the environment. This should generally never happen, but we can't645* control it, and can't control the version of fontconfig, so iff646* its not defined we set it to an empty value which is sufficient647* to prevent a crash. I considered unsetting it before exit, but648* it doesn't appear to work on Solaris, so I will leave it set.649*/650homeEnv = getenv("HOME");651if (homeEnv == NULL) {652putenv(homeEnvStr);653}654655return libfontconfig;656}657658typedef void* (FcFiniFuncType)();659660static void closeFontConfig(void* libfontconfig, jboolean fcFini) {661662/* NB FcFini is not in (eg) the Solaris 10 version of fontconfig. Its not663* clear if this means we are really leaking resources in those cases664* but it seems we should call this function when its available.665* But since the Swing GTK code may be still accessing the lib, its probably666* safest for now to just let this "leak" rather than potentially667* concurrently free global data still in use by other code.668*/669#if 0670if (fcFini) { /* release resources */671FcFiniFuncType FcFini = (FcFiniFuncType)dlsym(libfontconfig, "FcFini");672673if (FcFini != NULL) {674(*FcFini)();675}676}677#endif678dlclose(libfontconfig);679}680681typedef FcConfig* (*FcInitLoadConfigFuncType)();682typedef FcPattern* (*FcPatternBuildFuncType)(FcPattern *orig, ...);683typedef FcObjectSet* (*FcObjectSetFuncType)(const char *first, ...);684typedef FcFontSet* (*FcFontListFuncType)(FcConfig *config,685FcPattern *p,686FcObjectSet *os);687typedef FcResult (*FcPatternGetBoolFuncType)(const FcPattern *p,688const char *object,689int n,690FcBool *b);691typedef FcResult (*FcPatternGetIntegerFuncType)(const FcPattern *p,692const char *object,693int n,694int *i);695typedef FcResult (*FcPatternGetStringFuncType)(const FcPattern *p,696const char *object,697int n,698FcChar8 ** s);699typedef FcChar8* (*FcStrDirnameFuncType)(const FcChar8 *file);700typedef void (*FcPatternDestroyFuncType)(FcPattern *p);701typedef void (*FcFontSetDestroyFuncType)(FcFontSet *s);702typedef FcPattern* (*FcNameParseFuncType)(const FcChar8 *name);703typedef FcBool (*FcPatternAddStringFuncType)(FcPattern *p,704const char *object,705const FcChar8 *s);706typedef void (*FcDefaultSubstituteFuncType)(FcPattern *p);707typedef FcBool (*FcConfigSubstituteFuncType)(FcConfig *config,708FcPattern *p,709FcMatchKind kind);710typedef FcPattern* (*FcFontMatchFuncType)(FcConfig *config,711FcPattern *p,712FcResult *result);713typedef FcFontSet* (*FcFontSetCreateFuncType)();714typedef FcBool (*FcFontSetAddFuncType)(FcFontSet *s, FcPattern *font);715716typedef FcResult (*FcPatternGetCharSetFuncType)(FcPattern *p,717const char *object,718int n,719FcCharSet **c);720typedef FcFontSet* (*FcFontSortFuncType)(FcConfig *config,721FcPattern *p,722FcBool trim,723FcCharSet **csp,724FcResult *result);725typedef FcCharSet* (*FcCharSetUnionFuncType)(const FcCharSet *a,726const FcCharSet *b);727typedef FcChar32 (*FcCharSetSubtractCountFuncType)(const FcCharSet *a,728const FcCharSet *b);729730typedef int (*FcGetVersionFuncType)();731732typedef FcStrList* (*FcConfigGetCacheDirsFuncType)(FcConfig *config);733typedef FcChar8* (*FcStrListNextFuncType)(FcStrList *list);734typedef FcChar8* (*FcStrListDoneFuncType)(FcStrList *list);735736static char **getFontConfigLocations() {737738char **fontdirs;739int numdirs = 0;740FcInitLoadConfigFuncType FcInitLoadConfig;741FcPatternBuildFuncType FcPatternBuild;742FcObjectSetFuncType FcObjectSetBuild;743FcFontListFuncType FcFontList;744FcPatternGetStringFuncType FcPatternGetString;745FcStrDirnameFuncType FcStrDirname;746FcPatternDestroyFuncType FcPatternDestroy;747FcFontSetDestroyFuncType FcFontSetDestroy;748749FcConfig *fontconfig;750FcPattern *pattern;751FcObjectSet *objset;752FcFontSet *fontSet;753FcStrList *strList;754FcChar8 *str;755int i, f, found, len=0;756char **fontPath;757758void* libfontconfig = openFontConfig();759760if (libfontconfig == NULL) {761return NULL;762}763764FcPatternBuild =765(FcPatternBuildFuncType)dlsym(libfontconfig, "FcPatternBuild");766FcObjectSetBuild =767(FcObjectSetFuncType)dlsym(libfontconfig, "FcObjectSetBuild");768FcFontList =769(FcFontListFuncType)dlsym(libfontconfig, "FcFontList");770FcPatternGetString =771(FcPatternGetStringFuncType)dlsym(libfontconfig, "FcPatternGetString");772FcStrDirname =773(FcStrDirnameFuncType)dlsym(libfontconfig, "FcStrDirname");774FcPatternDestroy =775(FcPatternDestroyFuncType)dlsym(libfontconfig, "FcPatternDestroy");776FcFontSetDestroy =777(FcFontSetDestroyFuncType)dlsym(libfontconfig, "FcFontSetDestroy");778779if (FcPatternBuild == NULL ||780FcObjectSetBuild == NULL ||781FcPatternGetString == NULL ||782FcFontList == NULL ||783FcStrDirname == NULL ||784FcPatternDestroy == NULL ||785FcFontSetDestroy == NULL) { /* problem with the library: return. */786closeFontConfig(libfontconfig, JNI_FALSE);787return NULL;788}789790/* Make calls into the fontconfig library to build a search for791* outline fonts, and to get the set of full file paths from the matches.792* This set is returned from the call to FcFontList(..)793* We allocate an array of char* pointers sufficient to hold all794* the matches + 1 extra which ensures there will be a NULL after all795* valid entries.796* We call FcStrDirname strip the file name from the path, and797* check if we have yet seen this directory. If not we add a pointer to798* it into our array of char*. Note that FcStrDirname returns newly799* allocated storage so we can use this in the return char** value.800* Finally we clean up, freeing allocated resources, and return the801* array of unique directories.802*/803pattern = (*FcPatternBuild)(NULL, FC_OUTLINE, FcTypeBool, FcTrue, NULL);804objset = (*FcObjectSetBuild)(FC_FILE, NULL);805fontSet = (*FcFontList)(NULL, pattern, objset);806if (fontSet == NULL) {807/* FcFontList() may return NULL if fonts are not installed. */808fontdirs = NULL;809} else {810fontdirs = (char**)calloc(fontSet->nfont+1, sizeof(char*));811for (f=0; f < fontSet->nfont; f++) {812FcChar8 *file;813FcChar8 *dir;814if ((*FcPatternGetString)(fontSet->fonts[f], FC_FILE, 0, &file) ==815FcResultMatch) {816dir = (*FcStrDirname)(file);817found = 0;818for (i=0;i<numdirs; i++) {819if (strcmp(fontdirs[i], (char*)dir) == 0) {820found = 1;821break;822}823}824if (!found) {825fontdirs[numdirs++] = (char*)dir;826} else {827free((char*)dir);828}829}830}831/* Free fontset if one was returned */832(*FcFontSetDestroy)(fontSet);833}834835/* Free memory and close the ".so" */836(*FcPatternDestroy)(pattern);837closeFontConfig(libfontconfig, JNI_TRUE);838return fontdirs;839}840841/* These are copied from sun.awt.SunHints.842* Consider initialising them as ints using JNI for more robustness.843*/844#define TEXT_AA_OFF 1845#define TEXT_AA_ON 2846#define TEXT_AA_LCD_HRGB 4847#define TEXT_AA_LCD_HBGR 5848#define TEXT_AA_LCD_VRGB 6849#define TEXT_AA_LCD_VBGR 7850851JNIEXPORT jint JNICALL852Java_sun_font_FontConfigManager_getFontConfigAASettings853(JNIEnv *env, jclass obj, jstring localeStr, jstring fcNameStr) {854855FcNameParseFuncType FcNameParse;856FcPatternAddStringFuncType FcPatternAddString;857FcConfigSubstituteFuncType FcConfigSubstitute;858FcDefaultSubstituteFuncType FcDefaultSubstitute;859FcFontMatchFuncType FcFontMatch;860FcPatternGetBoolFuncType FcPatternGetBool;861FcPatternGetIntegerFuncType FcPatternGetInteger;862FcPatternDestroyFuncType FcPatternDestroy;863864FcPattern *pattern, *matchPattern;865FcResult result;866FcBool antialias = FcFalse;867int rgba = 0;868const char *locale=NULL, *fcName=NULL;869void* libfontconfig;870871if (fcNameStr == NULL || localeStr == NULL) {872return -1;873}874875fcName = (*env)->GetStringUTFChars(env, fcNameStr, 0);876if (fcName == NULL) {877return -1;878}879locale = (*env)->GetStringUTFChars(env, localeStr, 0);880881if ((libfontconfig = openFontConfig()) == NULL) {882(*env)->ReleaseStringUTFChars (env, fcNameStr, (const char*)fcName);883if (locale) {884(*env)->ReleaseStringUTFChars (env, localeStr,(const char*)locale);885}886return -1;887}888889FcNameParse = (FcNameParseFuncType)dlsym(libfontconfig, "FcNameParse");890FcPatternAddString =891(FcPatternAddStringFuncType)dlsym(libfontconfig, "FcPatternAddString");892FcConfigSubstitute =893(FcConfigSubstituteFuncType)dlsym(libfontconfig, "FcConfigSubstitute");894FcDefaultSubstitute = (FcDefaultSubstituteFuncType)895dlsym(libfontconfig, "FcDefaultSubstitute");896FcFontMatch = (FcFontMatchFuncType)dlsym(libfontconfig, "FcFontMatch");897FcPatternGetBool = (FcPatternGetBoolFuncType)898dlsym(libfontconfig, "FcPatternGetBool");899FcPatternGetInteger = (FcPatternGetIntegerFuncType)900dlsym(libfontconfig, "FcPatternGetInteger");901FcPatternDestroy =902(FcPatternDestroyFuncType)dlsym(libfontconfig, "FcPatternDestroy");903904if (FcNameParse == NULL ||905FcPatternAddString == NULL ||906FcConfigSubstitute == NULL ||907FcDefaultSubstitute == NULL ||908FcFontMatch == NULL ||909FcPatternGetBool == NULL ||910FcPatternGetInteger == NULL ||911FcPatternDestroy == NULL) { /* problem with the library: return. */912913(*env)->ReleaseStringUTFChars (env, fcNameStr, (const char*)fcName);914if (locale) {915(*env)->ReleaseStringUTFChars (env, localeStr,(const char*)locale);916}917closeFontConfig(libfontconfig, JNI_FALSE);918return -1;919}920921922pattern = (*FcNameParse)((FcChar8 *)fcName);923if (locale != NULL) {924(*FcPatternAddString)(pattern, FC_LANG, (unsigned char*)locale);925}926(*FcConfigSubstitute)(NULL, pattern, FcMatchPattern);927(*FcDefaultSubstitute)(pattern);928matchPattern = (*FcFontMatch)(NULL, pattern, &result);929/* Perhaps should call FcFontRenderPrepare() here as some pattern930* elements might change as a result of that call, but I'm not seeing931* any difference in testing.932*/933if (matchPattern) {934(*FcPatternGetBool)(matchPattern, FC_ANTIALIAS, 0, &antialias);935(*FcPatternGetInteger)(matchPattern, FC_RGBA, 0, &rgba);936(*FcPatternDestroy)(matchPattern);937}938(*FcPatternDestroy)(pattern);939940(*env)->ReleaseStringUTFChars (env, fcNameStr, (const char*)fcName);941if (locale) {942(*env)->ReleaseStringUTFChars (env, localeStr, (const char*)locale);943}944closeFontConfig(libfontconfig, JNI_TRUE);945946if (antialias == FcFalse) {947return TEXT_AA_OFF;948} else if (rgba <= FC_RGBA_UNKNOWN || rgba >= FC_RGBA_NONE) {949return TEXT_AA_ON;950} else {951switch (rgba) {952case FC_RGBA_RGB : return TEXT_AA_LCD_HRGB;953case FC_RGBA_BGR : return TEXT_AA_LCD_HBGR;954case FC_RGBA_VRGB : return TEXT_AA_LCD_VRGB;955case FC_RGBA_VBGR : return TEXT_AA_LCD_VBGR;956default : return TEXT_AA_LCD_HRGB; // should not get here.957}958}959}960961JNIEXPORT jint JNICALL962Java_sun_font_FontConfigManager_getFontConfigVersion963(JNIEnv *env, jclass obj) {964965void* libfontconfig;966FcGetVersionFuncType FcGetVersion;967int version = 0;968969if ((libfontconfig = openFontConfig()) == NULL) {970return 0;971}972973FcGetVersion = (FcGetVersionFuncType)dlsym(libfontconfig, "FcGetVersion");974975if (FcGetVersion == NULL) {976closeFontConfig(libfontconfig, JNI_FALSE);977return 0;978}979version = (*FcGetVersion)();980closeFontConfig(libfontconfig, JNI_FALSE);981982return version;983}984985986JNIEXPORT void JNICALL987Java_sun_font_FontConfigManager_getFontConfig988(JNIEnv *env, jclass obj, jstring localeStr, jobject fcInfoObj,989jobjectArray fcCompFontArray, jboolean includeFallbacks) {990991FcNameParseFuncType FcNameParse;992FcPatternAddStringFuncType FcPatternAddString;993FcConfigSubstituteFuncType FcConfigSubstitute;994FcDefaultSubstituteFuncType FcDefaultSubstitute;995FcFontMatchFuncType FcFontMatch;996FcPatternGetStringFuncType FcPatternGetString;997FcPatternDestroyFuncType FcPatternDestroy;998FcPatternGetCharSetFuncType FcPatternGetCharSet;999FcFontSortFuncType FcFontSort;1000FcFontSetDestroyFuncType FcFontSetDestroy;1001FcCharSetUnionFuncType FcCharSetUnion;1002FcCharSetSubtractCountFuncType FcCharSetSubtractCount;1003FcGetVersionFuncType FcGetVersion;1004FcConfigGetCacheDirsFuncType FcConfigGetCacheDirs;1005FcStrListNextFuncType FcStrListNext;1006FcStrListDoneFuncType FcStrListDone;10071008int i, arrlen;1009jobject fcCompFontObj;1010jstring fcNameStr, jstr;1011const char *locale, *fcName;1012FcPattern *pattern;1013FcResult result;1014void* libfontconfig;1015jfieldID fcNameID, fcFirstFontID, fcAllFontsID, fcVersionID, fcCacheDirsID;1016jfieldID familyNameID, styleNameID, fullNameID, fontFileID;1017jmethodID fcFontCons;1018char* debugMinGlyphsStr = getenv("J2D_DEBUG_MIN_GLYPHS");10191020CHECK_NULL(fcInfoObj);1021CHECK_NULL(fcCompFontArray);10221023jclass fcInfoClass =1024(*env)->FindClass(env, "sun/font/FontConfigManager$FontConfigInfo");1025CHECK_NULL(fcInfoClass);1026jclass fcCompFontClass =1027(*env)->FindClass(env, "sun/font/FontConfigManager$FcCompFont");1028CHECK_NULL(fcCompFontClass);1029jclass fcFontClass =1030(*env)->FindClass(env, "sun/font/FontConfigManager$FontConfigFont");1031CHECK_NULL(fcFontClass);103210331034CHECK_NULL(fcVersionID = (*env)->GetFieldID(env, fcInfoClass, "fcVersion", "I"));1035CHECK_NULL(fcCacheDirsID = (*env)->GetFieldID(env, fcInfoClass, "cacheDirs",1036"[Ljava/lang/String;"));1037CHECK_NULL(fcNameID = (*env)->GetFieldID(env, fcCompFontClass,1038"fcName", "Ljava/lang/String;"));1039CHECK_NULL(fcFirstFontID = (*env)->GetFieldID(env, fcCompFontClass, "firstFont",1040"Lsun/font/FontConfigManager$FontConfigFont;"));1041CHECK_NULL(fcAllFontsID = (*env)->GetFieldID(env, fcCompFontClass, "allFonts",1042"[Lsun/font/FontConfigManager$FontConfigFont;"));1043CHECK_NULL(fcFontCons = (*env)->GetMethodID(env, fcFontClass, "<init>", "()V"));1044CHECK_NULL(familyNameID = (*env)->GetFieldID(env, fcFontClass,1045"familyName", "Ljava/lang/String;"));1046CHECK_NULL(styleNameID = (*env)->GetFieldID(env, fcFontClass,1047"styleStr", "Ljava/lang/String;"));1048CHECK_NULL(fullNameID = (*env)->GetFieldID(env, fcFontClass,1049"fullName", "Ljava/lang/String;"));1050CHECK_NULL(fontFileID = (*env)->GetFieldID(env, fcFontClass,1051"fontFile", "Ljava/lang/String;"));10521053jclass fontUtilitiesClass =1054(*env)->FindClass(env, "sun/font/FontUtilities");1055CHECK_NULL(fontUtilitiesClass);1056jfieldID isOpenJDKID =1057(*env)->GetStaticFieldID(env, fontUtilitiesClass, "isOpenJDK", "Z");1058CHECK_NULL(isOpenJDKID);1059jboolean isOpenJDK =1060(*env)->GetStaticBooleanField(env, fontUtilitiesClass, isOpenJDKID);106110621063if ((libfontconfig = openFontConfig()) == NULL) {1064return;1065}10661067FcNameParse = (FcNameParseFuncType)dlsym(libfontconfig, "FcNameParse");1068FcPatternAddString =1069(FcPatternAddStringFuncType)dlsym(libfontconfig, "FcPatternAddString");1070FcConfigSubstitute =1071(FcConfigSubstituteFuncType)dlsym(libfontconfig, "FcConfigSubstitute");1072FcDefaultSubstitute = (FcDefaultSubstituteFuncType)1073dlsym(libfontconfig, "FcDefaultSubstitute");1074FcFontMatch = (FcFontMatchFuncType)dlsym(libfontconfig, "FcFontMatch");1075FcPatternGetString =1076(FcPatternGetStringFuncType)dlsym(libfontconfig, "FcPatternGetString");1077FcPatternDestroy =1078(FcPatternDestroyFuncType)dlsym(libfontconfig, "FcPatternDestroy");1079FcPatternGetCharSet =1080(FcPatternGetCharSetFuncType)dlsym(libfontconfig,1081"FcPatternGetCharSet");1082FcFontSort =1083(FcFontSortFuncType)dlsym(libfontconfig, "FcFontSort");1084FcFontSetDestroy =1085(FcFontSetDestroyFuncType)dlsym(libfontconfig, "FcFontSetDestroy");1086FcCharSetUnion =1087(FcCharSetUnionFuncType)dlsym(libfontconfig, "FcCharSetUnion");1088FcCharSetSubtractCount =1089(FcCharSetSubtractCountFuncType)dlsym(libfontconfig,1090"FcCharSetSubtractCount");1091FcGetVersion = (FcGetVersionFuncType)dlsym(libfontconfig, "FcGetVersion");10921093if (FcNameParse == NULL ||1094FcPatternAddString == NULL ||1095FcConfigSubstitute == NULL ||1096FcDefaultSubstitute == NULL ||1097FcFontMatch == NULL ||1098FcPatternGetString == NULL ||1099FcPatternDestroy == NULL ||1100FcPatternGetCharSet == NULL ||1101FcFontSetDestroy == NULL ||1102FcCharSetUnion == NULL ||1103FcGetVersion == NULL ||1104FcCharSetSubtractCount == NULL) {/* problem with the library: return.*/1105closeFontConfig(libfontconfig, JNI_FALSE);1106return;1107}11081109(*env)->SetIntField(env, fcInfoObj, fcVersionID, (*FcGetVersion)());11101111/* Optionally get the cache dir locations. This isn't1112* available until v 2.4.x, but this is OK since on those later versions1113* we can check the time stamps on the cache dirs to see if we1114* are out of date. There are a couple of assumptions here. First1115* that the time stamp on the directory changes when the contents are1116* updated. Secondly that the locations don't change. The latter is1117* most likely if a new version of fontconfig is installed, but we also1118* invalidate the cache if we detect that. Arguably even that is "rare",1119* and most likely is tied to an OS upgrade which gets a new file anyway.1120*/1121FcConfigGetCacheDirs =1122(FcConfigGetCacheDirsFuncType)dlsym(libfontconfig,1123"FcConfigGetCacheDirs");1124FcStrListNext =1125(FcStrListNextFuncType)dlsym(libfontconfig, "FcStrListNext");1126FcStrListDone =1127(FcStrListDoneFuncType)dlsym(libfontconfig, "FcStrListDone");1128if (FcStrListNext != NULL && FcStrListDone != NULL &&1129FcConfigGetCacheDirs != NULL) {11301131FcStrList* cacheDirs;1132FcChar8* cacheDir;1133int cnt = 0;1134jobject cacheDirArray =1135(*env)->GetObjectField(env, fcInfoObj, fcCacheDirsID);1136int max = (*env)->GetArrayLength(env, cacheDirArray);11371138cacheDirs = (*FcConfigGetCacheDirs)(NULL);1139if (cacheDirs != NULL) {1140while ((cnt < max) && (cacheDir = (*FcStrListNext)(cacheDirs))) {1141jstr = (*env)->NewStringUTF(env, (const char*)cacheDir);1142JNU_CHECK_EXCEPTION(env);11431144(*env)->SetObjectArrayElement(env, cacheDirArray, cnt++, jstr);1145}1146(*FcStrListDone)(cacheDirs);1147}1148}11491150locale = (*env)->GetStringUTFChars(env, localeStr, 0);1151if (locale == NULL) {1152(*env)->ExceptionClear(env);1153JNU_ThrowOutOfMemoryError(env, "Could not create locale");1154return;1155}11561157arrlen = (*env)->GetArrayLength(env, fcCompFontArray);1158for (i=0; i<arrlen; i++) {1159FcFontSet* fontset;1160int fn, j, fontCount, nfonts;1161unsigned int minGlyphs;1162FcChar8 **family, **styleStr, **fullname, **file;1163jarray fcFontArr;11641165fcCompFontObj = (*env)->GetObjectArrayElement(env, fcCompFontArray, i);1166fcNameStr =1167(jstring)((*env)->GetObjectField(env, fcCompFontObj, fcNameID));1168fcName = (*env)->GetStringUTFChars(env, fcNameStr, 0);1169if (fcName == NULL) {1170continue;1171}1172pattern = (*FcNameParse)((FcChar8 *)fcName);1173(*env)->ReleaseStringUTFChars(env, fcNameStr, (const char*)fcName);1174if (pattern == NULL) {1175closeFontConfig(libfontconfig, JNI_FALSE);1176return;1177}11781179/* locale may not usually be necessary as fontconfig appears to apply1180* this anyway based on the user's environment. However we want1181* to use the value of the JDK startup locale so this should take1182* care of it.1183*/1184if (locale != NULL) {1185(*FcPatternAddString)(pattern, FC_LANG, (unsigned char*)locale);1186}1187(*FcConfigSubstitute)(NULL, pattern, FcMatchPattern);1188(*FcDefaultSubstitute)(pattern);1189fontset = (*FcFontSort)(NULL, pattern, FcTrue, NULL, &result);1190if (fontset == NULL) {1191(*FcPatternDestroy)(pattern);1192closeFontConfig(libfontconfig, JNI_FALSE);1193return;1194}11951196/* fontconfig returned us "nfonts". If we are just getting the1197* first font, we set nfont to zero. Otherwise we use "nfonts".1198* Next create separate C arrrays of length nfonts for family file etc.1199* Inspect the returned fonts and the ones we like (adds enough glyphs)1200* are added to the arrays and we increment 'fontCount'.1201*/1202nfonts = fontset->nfont;1203family = (FcChar8**)calloc(nfonts, sizeof(FcChar8*));1204styleStr = (FcChar8**)calloc(nfonts, sizeof(FcChar8*));1205fullname = (FcChar8**)calloc(nfonts, sizeof(FcChar8*));1206file = (FcChar8**)calloc(nfonts, sizeof(FcChar8*));1207if (family == NULL || styleStr == NULL ||1208fullname == NULL || file == NULL) {1209if (family != NULL) {1210free(family);1211}1212if (styleStr != NULL) {1213free(styleStr);1214}1215if (fullname != NULL) {1216free(fullname);1217}1218if (file != NULL) {1219free(file);1220}1221(*FcPatternDestroy)(pattern);1222(*FcFontSetDestroy)(fontset);1223closeFontConfig(libfontconfig, JNI_FALSE);1224return;1225}1226fontCount = 0;1227minGlyphs = 20;1228if (debugMinGlyphsStr != NULL) {1229int val = minGlyphs;1230sscanf(debugMinGlyphsStr, "%5d", &val);1231if (val >= 0 && val <= 65536) {1232minGlyphs = val;1233}1234}1235FcCharSet *unionCharset = NULL;1236for (j=0; j<nfonts; j++) {1237FcPattern *fontPattern = fontset->fonts[j];1238FcChar8 *fontformat;1239FcCharSet *charset = NULL;12401241fontformat = NULL;1242(*FcPatternGetString)(fontPattern, FC_FONTFORMAT, 0, &fontformat);1243/* We only want TrueType fonts but some Linuxes still depend1244* on Type 1 fonts for some Locale support, so we'll allow1245* them there.1246*/1247if (fontformat != NULL1248&& (strcmp((char*)fontformat, "TrueType") != 0)1249#if defined(__linux__) || defined(_AIX)1250&& (strcmp((char*)fontformat, "Type 1") != 0)1251&& !(isOpenJDK && (strcmp((char*)fontformat, "CFF") == 0))1252#endif1253) {1254continue;1255}1256result = (*FcPatternGetCharSet)(fontPattern,1257FC_CHARSET, 0, &charset);1258if (result != FcResultMatch) {1259free(family);1260free(fullname);1261free(styleStr);1262free(file);1263(*FcPatternDestroy)(pattern);1264(*FcFontSetDestroy)(fontset);1265closeFontConfig(libfontconfig, JNI_FALSE);1266return;1267}12681269/* We don't want 20 or 30 fonts, so once we hit 10 fonts,1270* then require that they really be adding value. Too many1271* adversely affects load time for minimal value-add.1272* This is still likely far more than we've had in the past.1273*/1274if (j==10) {1275minGlyphs = 50;1276}1277if (unionCharset == NULL) {1278unionCharset = charset;1279} else {1280if ((*FcCharSetSubtractCount)(charset, unionCharset)1281> minGlyphs) {1282unionCharset = (* FcCharSetUnion)(unionCharset, charset);1283} else {1284continue;1285}1286}12871288fontCount++; // found a font we will use.1289(*FcPatternGetString)(fontPattern, FC_FILE, 0, &file[j]);1290(*FcPatternGetString)(fontPattern, FC_FAMILY, 0, &family[j]);1291(*FcPatternGetString)(fontPattern, FC_STYLE, 0, &styleStr[j]);1292(*FcPatternGetString)(fontPattern, FC_FULLNAME, 0, &fullname[j]);1293if (!includeFallbacks) {1294break;1295}1296if (fontCount == 254) {1297break; // CompositeFont will only use up to 254 slots from here.1298}1299}13001301/* Once we get here 'fontCount' is the number of returned fonts1302* we actually want to use, so we create 'fcFontArr' of that length.1303* The non-null entries of "family[]" etc are those fonts.1304* Then loop again over all nfonts adding just those non-null ones1305* to 'fcFontArr'. If its null (we didn't want the font)1306* then we don't enter the main body.1307* So we should never get more than 'fontCount' entries.1308*/1309if (includeFallbacks) {1310fcFontArr =1311(*env)->NewObjectArray(env, fontCount, fcFontClass, NULL);1312if (IS_NULL(fcFontArr)) {1313free(family);1314free(fullname);1315free(styleStr);1316free(file);1317(*FcPatternDestroy)(pattern);1318(*FcFontSetDestroy)(fontset);1319closeFontConfig(libfontconfig, JNI_FALSE);1320return;1321}1322(*env)->SetObjectField(env,fcCompFontObj, fcAllFontsID, fcFontArr);1323}1324fn=0;13251326for (j=0;j<nfonts;j++) {1327if (family[j] != NULL) {1328jobject fcFont =1329(*env)->NewObject(env, fcFontClass, fcFontCons);1330if (IS_NULL(fcFont)) break;1331jstr = (*env)->NewStringUTF(env, (const char*)family[j]);1332if (IS_NULL(jstr)) break;1333(*env)->SetObjectField(env, fcFont, familyNameID, jstr);1334if (file[j] != NULL) {1335jstr = (*env)->NewStringUTF(env, (const char*)file[j]);1336if (IS_NULL(jstr)) break;1337(*env)->SetObjectField(env, fcFont, fontFileID, jstr);1338}1339if (styleStr[j] != NULL) {1340jstr = (*env)->NewStringUTF(env, (const char*)styleStr[j]);1341if (IS_NULL(jstr)) break;1342(*env)->SetObjectField(env, fcFont, styleNameID, jstr);1343}1344if (fullname[j] != NULL) {1345jstr = (*env)->NewStringUTF(env, (const char*)fullname[j]);1346if (IS_NULL(jstr)) break;1347(*env)->SetObjectField(env, fcFont, fullNameID, jstr);1348}1349if (fn==0) {1350(*env)->SetObjectField(env, fcCompFontObj,1351fcFirstFontID, fcFont);1352}1353if (includeFallbacks) {1354(*env)->SetObjectArrayElement(env, fcFontArr, fn++,fcFont);1355} else {1356break;1357}1358}1359}1360(*FcFontSetDestroy)(fontset);1361(*FcPatternDestroy)(pattern);1362free(family);1363free(styleStr);1364free(fullname);1365free(file);1366}13671368/* release resources and close the ".so" */13691370if (locale) {1371(*env)->ReleaseStringUTFChars (env, localeStr, (const char*)locale);1372}1373closeFontConfig(libfontconfig, JNI_TRUE);1374}137513761377