Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/solaris/native/sun/awt/fontpath.c
32287 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}567568ret = (*env)->NewStringUTF(env, ptr);569return ret;570}571572#include <dlfcn.h>573574#include <fontconfig/fontconfig.h>575576577static void* openFontConfig() {578579char *homeEnv;580static char *homeEnvStr = "HOME="; /* must be static */581void* libfontconfig = NULL;582#ifdef __solaris__583#define SYSINFOBUFSZ 8584char sysinfobuf[SYSINFOBUFSZ];585#endif586587/* Private workaround to not use fontconfig library.588* May be useful during testing/debugging589*/590char *useFC = getenv("USE_J2D_FONTCONFIG");591if (useFC != NULL && !strcmp(useFC, "no")) {592return NULL;593}594595#ifdef __solaris__596/* fontconfig is likely not properly configured on S8/S9 - skip it,597* although allow user to override this behaviour with an env. variable598* ie if USE_J2D_FONTCONFIG=yes then we skip this test.599* NB "4" is the length of a string which matches our patterns.600*/601if (useFC == NULL || strcmp(useFC, "yes")) {602if (sysinfo(SI_RELEASE, sysinfobuf, SYSINFOBUFSZ) == 4) {603if ((!strcmp(sysinfobuf, "5.8") || !strcmp(sysinfobuf, "5.9"))) {604return NULL;605}606}607}608#endif609610#if defined(_AIX)611/* On AIX, fontconfig is not a standard package supported by IBM.612* instead it has to be installed from the "AIX Toolbox for Linux Applications"613* site http://www-03.ibm.com/systems/power/software/aix/linux/toolbox/alpha.html614* and will be installed under /opt/freeware/lib/libfontconfig.a.615* Notice that the archive contains the real 32- and 64-bit shared libraries.616* We first try to load 'libfontconfig.so' from the default library path in the617* case the user has installed a private version of the library and if that618* doesn't succeed, we try the version from /opt/freeware/lib/libfontconfig.a619*/620libfontconfig = dlopen("libfontconfig.so", RTLD_LOCAL|RTLD_LAZY);621if (libfontconfig == NULL) {622libfontconfig = dlopen("/opt/freeware/lib/libfontconfig.a(libfontconfig.so.1)", RTLD_MEMBER|RTLD_LOCAL|RTLD_LAZY);623if (libfontconfig == NULL) {624return NULL;625}626}627#else628/* 64 bit sparc should pick up the right version from the lib path.629* New features may be added to libfontconfig, this is expected to630* be compatible with old features, but we may need to start631* distinguishing the library version, to know whether to expect632* certain symbols - and functionality - to be available.633* Also add explicit search for .so.1 in case .so symlink doesn't exist.634*/635libfontconfig = dlopen(FONTCONFIG_DLL_VERSIONED, RTLD_LOCAL|RTLD_LAZY);636if (libfontconfig == NULL) {637libfontconfig = dlopen(FONTCONFIG_DLL, RTLD_LOCAL|RTLD_LAZY);638if (libfontconfig == NULL) {639return NULL;640}641}642#endif643644/* Version 1.0 of libfontconfig crashes if HOME isn't defined in645* the environment. This should generally never happen, but we can't646* control it, and can't control the version of fontconfig, so iff647* its not defined we set it to an empty value which is sufficient648* to prevent a crash. I considered unsetting it before exit, but649* it doesn't appear to work on Solaris, so I will leave it set.650*/651homeEnv = getenv("HOME");652if (homeEnv == NULL) {653putenv(homeEnvStr);654}655656return libfontconfig;657}658659typedef void* (FcFiniFuncType)();660661static void closeFontConfig(void* libfontconfig, jboolean fcFini) {662663/* NB FcFini is not in (eg) the Solaris 10 version of fontconfig. Its not664* clear if this means we are really leaking resources in those cases665* but it seems we should call this function when its available.666* But since the Swing GTK code may be still accessing the lib, its probably667* safest for now to just let this "leak" rather than potentially668* concurrently free global data still in use by other code.669*/670#if 0671if (fcFini) { /* release resources */672FcFiniFuncType FcFini = (FcFiniFuncType)dlsym(libfontconfig, "FcFini");673674if (FcFini != NULL) {675(*FcFini)();676}677}678#endif679dlclose(libfontconfig);680}681682typedef FcConfig* (*FcInitLoadConfigFuncType)();683typedef FcPattern* (*FcPatternBuildFuncType)(FcPattern *orig, ...);684typedef FcObjectSet* (*FcObjectSetFuncType)(const char *first, ...);685typedef FcFontSet* (*FcFontListFuncType)(FcConfig *config,686FcPattern *p,687FcObjectSet *os);688typedef FcResult (*FcPatternGetBoolFuncType)(const FcPattern *p,689const char *object,690int n,691FcBool *b);692typedef FcResult (*FcPatternGetIntegerFuncType)(const FcPattern *p,693const char *object,694int n,695int *i);696typedef FcResult (*FcPatternGetStringFuncType)(const FcPattern *p,697const char *object,698int n,699FcChar8 ** s);700typedef FcChar8* (*FcStrDirnameFuncType)(const FcChar8 *file);701typedef void (*FcPatternDestroyFuncType)(FcPattern *p);702typedef void (*FcFontSetDestroyFuncType)(FcFontSet *s);703typedef FcPattern* (*FcNameParseFuncType)(const FcChar8 *name);704typedef FcBool (*FcPatternAddStringFuncType)(FcPattern *p,705const char *object,706const FcChar8 *s);707typedef void (*FcDefaultSubstituteFuncType)(FcPattern *p);708typedef FcBool (*FcConfigSubstituteFuncType)(FcConfig *config,709FcPattern *p,710FcMatchKind kind);711typedef FcPattern* (*FcFontMatchFuncType)(FcConfig *config,712FcPattern *p,713FcResult *result);714typedef FcFontSet* (*FcFontSetCreateFuncType)();715typedef FcBool (*FcFontSetAddFuncType)(FcFontSet *s, FcPattern *font);716717typedef FcResult (*FcPatternGetCharSetFuncType)(FcPattern *p,718const char *object,719int n,720FcCharSet **c);721typedef FcFontSet* (*FcFontSortFuncType)(FcConfig *config,722FcPattern *p,723FcBool trim,724FcCharSet **csp,725FcResult *result);726typedef FcCharSet* (*FcCharSetUnionFuncType)(const FcCharSet *a,727const FcCharSet *b);728typedef FcChar32 (*FcCharSetSubtractCountFuncType)(const FcCharSet *a,729const FcCharSet *b);730731typedef int (*FcGetVersionFuncType)();732733typedef FcStrList* (*FcConfigGetCacheDirsFuncType)(FcConfig *config);734typedef FcChar8* (*FcStrListNextFuncType)(FcStrList *list);735typedef FcChar8* (*FcStrListDoneFuncType)(FcStrList *list);736737static char **getFontConfigLocations() {738739char **fontdirs;740int numdirs = 0;741FcInitLoadConfigFuncType FcInitLoadConfig;742FcPatternBuildFuncType FcPatternBuild;743FcObjectSetFuncType FcObjectSetBuild;744FcFontListFuncType FcFontList;745FcPatternGetStringFuncType FcPatternGetString;746FcStrDirnameFuncType FcStrDirname;747FcPatternDestroyFuncType FcPatternDestroy;748FcFontSetDestroyFuncType FcFontSetDestroy;749750FcConfig *fontconfig;751FcPattern *pattern;752FcObjectSet *objset;753FcFontSet *fontSet;754FcStrList *strList;755FcChar8 *str;756int i, f, found, len=0;757char **fontPath;758759void* libfontconfig = openFontConfig();760761if (libfontconfig == NULL) {762return NULL;763}764765FcPatternBuild =766(FcPatternBuildFuncType)dlsym(libfontconfig, "FcPatternBuild");767FcObjectSetBuild =768(FcObjectSetFuncType)dlsym(libfontconfig, "FcObjectSetBuild");769FcFontList =770(FcFontListFuncType)dlsym(libfontconfig, "FcFontList");771FcPatternGetString =772(FcPatternGetStringFuncType)dlsym(libfontconfig, "FcPatternGetString");773FcStrDirname =774(FcStrDirnameFuncType)dlsym(libfontconfig, "FcStrDirname");775FcPatternDestroy =776(FcPatternDestroyFuncType)dlsym(libfontconfig, "FcPatternDestroy");777FcFontSetDestroy =778(FcFontSetDestroyFuncType)dlsym(libfontconfig, "FcFontSetDestroy");779780if (FcPatternBuild == NULL ||781FcObjectSetBuild == NULL ||782FcPatternGetString == NULL ||783FcFontList == NULL ||784FcStrDirname == NULL ||785FcPatternDestroy == NULL ||786FcFontSetDestroy == NULL) { /* problem with the library: return. */787closeFontConfig(libfontconfig, JNI_FALSE);788return NULL;789}790791/* Make calls into the fontconfig library to build a search for792* outline fonts, and to get the set of full file paths from the matches.793* This set is returned from the call to FcFontList(..)794* We allocate an array of char* pointers sufficient to hold all795* the matches + 1 extra which ensures there will be a NULL after all796* valid entries.797* We call FcStrDirname strip the file name from the path, and798* check if we have yet seen this directory. If not we add a pointer to799* it into our array of char*. Note that FcStrDirname returns newly800* allocated storage so we can use this in the return char** value.801* Finally we clean up, freeing allocated resources, and return the802* array of unique directories.803*/804pattern = (*FcPatternBuild)(NULL, FC_OUTLINE, FcTypeBool, FcTrue, NULL);805objset = (*FcObjectSetBuild)(FC_FILE, NULL);806fontSet = (*FcFontList)(NULL, pattern, objset);807if (fontSet == NULL) {808/* FcFontList() may return NULL if fonts are not installed. */809fontdirs = NULL;810} else {811fontdirs = (char**)calloc(fontSet->nfont+1, sizeof(char*));812for (f=0; f < fontSet->nfont; f++) {813FcChar8 *file;814FcChar8 *dir;815if ((*FcPatternGetString)(fontSet->fonts[f], FC_FILE, 0, &file) ==816FcResultMatch) {817dir = (*FcStrDirname)(file);818found = 0;819for (i=0;i<numdirs; i++) {820if (strcmp(fontdirs[i], (char*)dir) == 0) {821found = 1;822break;823}824}825if (!found) {826fontdirs[numdirs++] = (char*)dir;827} else {828free((char*)dir);829}830}831}832/* Free fontset if one was returned */833(*FcFontSetDestroy)(fontSet);834}835836/* Free memory and close the ".so" */837(*FcPatternDestroy)(pattern);838closeFontConfig(libfontconfig, JNI_TRUE);839return fontdirs;840}841842/* These are copied from sun.awt.SunHints.843* Consider initialising them as ints using JNI for more robustness.844*/845#define TEXT_AA_OFF 1846#define TEXT_AA_ON 2847#define TEXT_AA_LCD_HRGB 4848#define TEXT_AA_LCD_HBGR 5849#define TEXT_AA_LCD_VRGB 6850#define TEXT_AA_LCD_VBGR 7851852JNIEXPORT jint JNICALL853Java_sun_font_FontConfigManager_getFontConfigAASettings854(JNIEnv *env, jclass obj, jstring localeStr, jstring fcNameStr) {855856FcNameParseFuncType FcNameParse;857FcPatternAddStringFuncType FcPatternAddString;858FcConfigSubstituteFuncType FcConfigSubstitute;859FcDefaultSubstituteFuncType FcDefaultSubstitute;860FcFontMatchFuncType FcFontMatch;861FcPatternGetBoolFuncType FcPatternGetBool;862FcPatternGetIntegerFuncType FcPatternGetInteger;863FcPatternDestroyFuncType FcPatternDestroy;864865FcPattern *pattern, *matchPattern;866FcResult result;867FcBool antialias = FcFalse;868int rgba = 0;869const char *locale=NULL, *fcName=NULL;870void* libfontconfig;871872if (fcNameStr == NULL || localeStr == NULL) {873return -1;874}875876fcName = (*env)->GetStringUTFChars(env, fcNameStr, 0);877if (fcName == NULL) {878return -1;879}880locale = (*env)->GetStringUTFChars(env, localeStr, 0);881882if ((libfontconfig = openFontConfig()) == NULL) {883(*env)->ReleaseStringUTFChars (env, fcNameStr, (const char*)fcName);884if (locale) {885(*env)->ReleaseStringUTFChars (env, localeStr,(const char*)locale);886}887return -1;888}889890FcNameParse = (FcNameParseFuncType)dlsym(libfontconfig, "FcNameParse");891FcPatternAddString =892(FcPatternAddStringFuncType)dlsym(libfontconfig, "FcPatternAddString");893FcConfigSubstitute =894(FcConfigSubstituteFuncType)dlsym(libfontconfig, "FcConfigSubstitute");895FcDefaultSubstitute = (FcDefaultSubstituteFuncType)896dlsym(libfontconfig, "FcDefaultSubstitute");897FcFontMatch = (FcFontMatchFuncType)dlsym(libfontconfig, "FcFontMatch");898FcPatternGetBool = (FcPatternGetBoolFuncType)899dlsym(libfontconfig, "FcPatternGetBool");900FcPatternGetInteger = (FcPatternGetIntegerFuncType)901dlsym(libfontconfig, "FcPatternGetInteger");902FcPatternDestroy =903(FcPatternDestroyFuncType)dlsym(libfontconfig, "FcPatternDestroy");904905if (FcNameParse == NULL ||906FcPatternAddString == NULL ||907FcConfigSubstitute == NULL ||908FcDefaultSubstitute == NULL ||909FcFontMatch == NULL ||910FcPatternGetBool == NULL ||911FcPatternGetInteger == NULL ||912FcPatternDestroy == NULL) { /* problem with the library: return. */913914(*env)->ReleaseStringUTFChars (env, fcNameStr, (const char*)fcName);915if (locale) {916(*env)->ReleaseStringUTFChars (env, localeStr,(const char*)locale);917}918closeFontConfig(libfontconfig, JNI_FALSE);919return -1;920}921922923pattern = (*FcNameParse)((FcChar8 *)fcName);924if (locale != NULL) {925(*FcPatternAddString)(pattern, FC_LANG, (unsigned char*)locale);926}927(*FcConfigSubstitute)(NULL, pattern, FcMatchPattern);928(*FcDefaultSubstitute)(pattern);929matchPattern = (*FcFontMatch)(NULL, pattern, &result);930/* Perhaps should call FcFontRenderPrepare() here as some pattern931* elements might change as a result of that call, but I'm not seeing932* any difference in testing.933*/934if (matchPattern) {935(*FcPatternGetBool)(matchPattern, FC_ANTIALIAS, 0, &antialias);936(*FcPatternGetInteger)(matchPattern, FC_RGBA, 0, &rgba);937(*FcPatternDestroy)(matchPattern);938}939(*FcPatternDestroy)(pattern);940941(*env)->ReleaseStringUTFChars (env, fcNameStr, (const char*)fcName);942if (locale) {943(*env)->ReleaseStringUTFChars (env, localeStr, (const char*)locale);944}945closeFontConfig(libfontconfig, JNI_TRUE);946947if (antialias == FcFalse) {948return TEXT_AA_OFF;949} else if (rgba <= FC_RGBA_UNKNOWN || rgba >= FC_RGBA_NONE) {950return TEXT_AA_ON;951} else {952switch (rgba) {953case FC_RGBA_RGB : return TEXT_AA_LCD_HRGB;954case FC_RGBA_BGR : return TEXT_AA_LCD_HBGR;955case FC_RGBA_VRGB : return TEXT_AA_LCD_VRGB;956case FC_RGBA_VBGR : return TEXT_AA_LCD_VBGR;957default : return TEXT_AA_LCD_HRGB; // should not get here.958}959}960}961962JNIEXPORT jint JNICALL963Java_sun_font_FontConfigManager_getFontConfigVersion964(JNIEnv *env, jclass obj) {965966void* libfontconfig;967FcGetVersionFuncType FcGetVersion;968int version = 0;969970if ((libfontconfig = openFontConfig()) == NULL) {971return 0;972}973974FcGetVersion = (FcGetVersionFuncType)dlsym(libfontconfig, "FcGetVersion");975976if (FcGetVersion == NULL) {977closeFontConfig(libfontconfig, JNI_FALSE);978return 0;979}980version = (*FcGetVersion)();981closeFontConfig(libfontconfig, JNI_FALSE);982983return version;984}985986987JNIEXPORT void JNICALL988Java_sun_font_FontConfigManager_getFontConfig989(JNIEnv *env, jclass obj, jstring localeStr, jobject fcInfoObj,990jobjectArray fcCompFontArray, jboolean includeFallbacks) {991992FcNameParseFuncType FcNameParse;993FcPatternAddStringFuncType FcPatternAddString;994FcConfigSubstituteFuncType FcConfigSubstitute;995FcDefaultSubstituteFuncType FcDefaultSubstitute;996FcFontMatchFuncType FcFontMatch;997FcPatternGetStringFuncType FcPatternGetString;998FcPatternDestroyFuncType FcPatternDestroy;999FcPatternGetCharSetFuncType FcPatternGetCharSet;1000FcFontSortFuncType FcFontSort;1001FcFontSetDestroyFuncType FcFontSetDestroy;1002FcCharSetUnionFuncType FcCharSetUnion;1003FcCharSetSubtractCountFuncType FcCharSetSubtractCount;1004FcGetVersionFuncType FcGetVersion;1005FcConfigGetCacheDirsFuncType FcConfigGetCacheDirs;1006FcStrListNextFuncType FcStrListNext;1007FcStrListDoneFuncType FcStrListDone;10081009int i, arrlen;1010jobject fcCompFontObj;1011jstring fcNameStr, jstr;1012const char *locale, *fcName;1013FcPattern *pattern;1014FcResult result;1015void* libfontconfig;1016jfieldID fcNameID, fcFirstFontID, fcAllFontsID, fcVersionID, fcCacheDirsID;1017jfieldID familyNameID, styleNameID, fullNameID, fontFileID;1018jmethodID fcFontCons;1019char* debugMinGlyphsStr = getenv("J2D_DEBUG_MIN_GLYPHS");10201021CHECK_NULL(fcInfoObj);1022CHECK_NULL(fcCompFontArray);10231024jclass fcInfoClass =1025(*env)->FindClass(env, "sun/font/FontConfigManager$FontConfigInfo");1026CHECK_NULL(fcInfoClass);1027jclass fcCompFontClass =1028(*env)->FindClass(env, "sun/font/FontConfigManager$FcCompFont");1029CHECK_NULL(fcCompFontClass);1030jclass fcFontClass =1031(*env)->FindClass(env, "sun/font/FontConfigManager$FontConfigFont");1032CHECK_NULL(fcFontClass);103310341035CHECK_NULL(fcVersionID = (*env)->GetFieldID(env, fcInfoClass, "fcVersion", "I"));1036CHECK_NULL(fcCacheDirsID = (*env)->GetFieldID(env, fcInfoClass, "cacheDirs",1037"[Ljava/lang/String;"));1038CHECK_NULL(fcNameID = (*env)->GetFieldID(env, fcCompFontClass,1039"fcName", "Ljava/lang/String;"));1040CHECK_NULL(fcFirstFontID = (*env)->GetFieldID(env, fcCompFontClass, "firstFont",1041"Lsun/font/FontConfigManager$FontConfigFont;"));1042CHECK_NULL(fcAllFontsID = (*env)->GetFieldID(env, fcCompFontClass, "allFonts",1043"[Lsun/font/FontConfigManager$FontConfigFont;"));1044CHECK_NULL(fcFontCons = (*env)->GetMethodID(env, fcFontClass, "<init>", "()V"));1045CHECK_NULL(familyNameID = (*env)->GetFieldID(env, fcFontClass,1046"familyName", "Ljava/lang/String;"));1047CHECK_NULL(styleNameID = (*env)->GetFieldID(env, fcFontClass,1048"styleStr", "Ljava/lang/String;"));1049CHECK_NULL(fullNameID = (*env)->GetFieldID(env, fcFontClass,1050"fullName", "Ljava/lang/String;"));1051CHECK_NULL(fontFileID = (*env)->GetFieldID(env, fcFontClass,1052"fontFile", "Ljava/lang/String;"));10531054jclass fontUtilitiesClass =1055(*env)->FindClass(env, "sun/font/FontUtilities");1056CHECK_NULL(fontUtilitiesClass);1057jfieldID isOpenJDKID =1058(*env)->GetStaticFieldID(env, fontUtilitiesClass, "isOpenJDK", "Z");1059CHECK_NULL(isOpenJDKID);1060jboolean isOpenJDK =1061(*env)->GetStaticBooleanField(env, fontUtilitiesClass, isOpenJDKID);106210631064if ((libfontconfig = openFontConfig()) == NULL) {1065return;1066}10671068FcNameParse = (FcNameParseFuncType)dlsym(libfontconfig, "FcNameParse");1069FcPatternAddString =1070(FcPatternAddStringFuncType)dlsym(libfontconfig, "FcPatternAddString");1071FcConfigSubstitute =1072(FcConfigSubstituteFuncType)dlsym(libfontconfig, "FcConfigSubstitute");1073FcDefaultSubstitute = (FcDefaultSubstituteFuncType)1074dlsym(libfontconfig, "FcDefaultSubstitute");1075FcFontMatch = (FcFontMatchFuncType)dlsym(libfontconfig, "FcFontMatch");1076FcPatternGetString =1077(FcPatternGetStringFuncType)dlsym(libfontconfig, "FcPatternGetString");1078FcPatternDestroy =1079(FcPatternDestroyFuncType)dlsym(libfontconfig, "FcPatternDestroy");1080FcPatternGetCharSet =1081(FcPatternGetCharSetFuncType)dlsym(libfontconfig,1082"FcPatternGetCharSet");1083FcFontSort =1084(FcFontSortFuncType)dlsym(libfontconfig, "FcFontSort");1085FcFontSetDestroy =1086(FcFontSetDestroyFuncType)dlsym(libfontconfig, "FcFontSetDestroy");1087FcCharSetUnion =1088(FcCharSetUnionFuncType)dlsym(libfontconfig, "FcCharSetUnion");1089FcCharSetSubtractCount =1090(FcCharSetSubtractCountFuncType)dlsym(libfontconfig,1091"FcCharSetSubtractCount");1092FcGetVersion = (FcGetVersionFuncType)dlsym(libfontconfig, "FcGetVersion");10931094if (FcNameParse == NULL ||1095FcPatternAddString == NULL ||1096FcConfigSubstitute == NULL ||1097FcDefaultSubstitute == NULL ||1098FcFontMatch == NULL ||1099FcPatternGetString == NULL ||1100FcPatternDestroy == NULL ||1101FcPatternGetCharSet == NULL ||1102FcFontSetDestroy == NULL ||1103FcCharSetUnion == NULL ||1104FcGetVersion == NULL ||1105FcCharSetSubtractCount == NULL) {/* problem with the library: return.*/1106closeFontConfig(libfontconfig, JNI_FALSE);1107return;1108}11091110(*env)->SetIntField(env, fcInfoObj, fcVersionID, (*FcGetVersion)());11111112/* Optionally get the cache dir locations. This isn't1113* available until v 2.4.x, but this is OK since on those later versions1114* we can check the time stamps on the cache dirs to see if we1115* are out of date. There are a couple of assumptions here. First1116* that the time stamp on the directory changes when the contents are1117* updated. Secondly that the locations don't change. The latter is1118* most likely if a new version of fontconfig is installed, but we also1119* 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*/1122FcConfigGetCacheDirs =1123(FcConfigGetCacheDirsFuncType)dlsym(libfontconfig,1124"FcConfigGetCacheDirs");1125FcStrListNext =1126(FcStrListNextFuncType)dlsym(libfontconfig, "FcStrListNext");1127FcStrListDone =1128(FcStrListDoneFuncType)dlsym(libfontconfig, "FcStrListDone");1129if (FcStrListNext != NULL && FcStrListDone != NULL &&1130FcConfigGetCacheDirs != NULL) {11311132FcStrList* cacheDirs;1133FcChar8* cacheDir;1134int cnt = 0;1135jobject cacheDirArray =1136(*env)->GetObjectField(env, fcInfoObj, fcCacheDirsID);1137int max = (*env)->GetArrayLength(env, cacheDirArray);11381139cacheDirs = (*FcConfigGetCacheDirs)(NULL);1140if (cacheDirs != NULL) {1141while ((cnt < max) && (cacheDir = (*FcStrListNext)(cacheDirs))) {1142jstr = (*env)->NewStringUTF(env, (const char*)cacheDir);1143JNU_CHECK_EXCEPTION(env);11441145(*env)->SetObjectArrayElement(env, cacheDirArray, cnt++, jstr);1146}1147(*FcStrListDone)(cacheDirs);1148}1149}11501151locale = (*env)->GetStringUTFChars(env, localeStr, 0);1152if (locale == NULL) {1153(*env)->ExceptionClear(env);1154JNU_ThrowOutOfMemoryError(env, "Could not create locale");1155return;1156}11571158arrlen = (*env)->GetArrayLength(env, fcCompFontArray);1159for (i=0; i<arrlen; i++) {1160FcFontSet* fontset;1161int fn, j, fontCount, nfonts;1162unsigned int minGlyphs;1163FcChar8 **family, **styleStr, **fullname, **file;1164jarray fcFontArr;11651166fcCompFontObj = (*env)->GetObjectArrayElement(env, fcCompFontArray, i);1167fcNameStr =1168(jstring)((*env)->GetObjectField(env, fcCompFontObj, fcNameID));1169fcName = (*env)->GetStringUTFChars(env, fcNameStr, 0);1170if (fcName == NULL) {1171continue;1172}1173pattern = (*FcNameParse)((FcChar8 *)fcName);1174(*env)->ReleaseStringUTFChars(env, fcNameStr, (const char*)fcName);1175if (pattern == NULL) {1176closeFontConfig(libfontconfig, JNI_FALSE);1177return;1178}11791180/* locale may not usually be necessary as fontconfig appears to apply1181* this anyway based on the user's environment. However we want1182* to use the value of the JDK startup locale so this should take1183* care of it.1184*/1185if (locale != NULL) {1186(*FcPatternAddString)(pattern, FC_LANG, (unsigned char*)locale);1187}1188(*FcConfigSubstitute)(NULL, pattern, FcMatchPattern);1189(*FcDefaultSubstitute)(pattern);1190fontset = (*FcFontSort)(NULL, pattern, FcTrue, NULL, &result);1191if (fontset == NULL) {1192(*FcPatternDestroy)(pattern);1193closeFontConfig(libfontconfig, JNI_FALSE);1194return;1195}11961197/* fontconfig returned us "nfonts". If we are just getting the1198* first font, we set nfont to zero. Otherwise we use "nfonts".1199* Next create separate C arrrays of length nfonts for family file etc.1200* Inspect the returned fonts and the ones we like (adds enough glyphs)1201* are added to the arrays and we increment 'fontCount'.1202*/1203nfonts = fontset->nfont;1204family = (FcChar8**)calloc(nfonts, sizeof(FcChar8*));1205styleStr = (FcChar8**)calloc(nfonts, sizeof(FcChar8*));1206fullname = (FcChar8**)calloc(nfonts, sizeof(FcChar8*));1207file = (FcChar8**)calloc(nfonts, sizeof(FcChar8*));1208if (family == NULL || styleStr == NULL ||1209fullname == NULL || file == NULL) {1210if (family != NULL) {1211free(family);1212}1213if (styleStr != NULL) {1214free(styleStr);1215}1216if (fullname != NULL) {1217free(fullname);1218}1219if (file != NULL) {1220free(file);1221}1222(*FcPatternDestroy)(pattern);1223(*FcFontSetDestroy)(fontset);1224closeFontConfig(libfontconfig, JNI_FALSE);1225return;1226}1227fontCount = 0;1228minGlyphs = 20;1229if (debugMinGlyphsStr != NULL) {1230int val = minGlyphs;1231sscanf(debugMinGlyphsStr, "%5d", &val);1232if (val >= 0 && val <= 65536) {1233minGlyphs = val;1234}1235}1236FcCharSet *unionCharset = NULL;1237for (j=0; j<nfonts; j++) {1238FcPattern *fontPattern = fontset->fonts[j];1239FcChar8 *fontformat;1240FcCharSet *charset = NULL;12411242fontformat = NULL;1243(*FcPatternGetString)(fontPattern, FC_FONTFORMAT, 0, &fontformat);1244/* We only want TrueType fonts but some Linuxes still depend1245* on Type 1 fonts for some Locale support, so we'll allow1246* them there.1247*/1248if (fontformat != NULL1249&& (strcmp((char*)fontformat, "TrueType") != 0)1250#if defined(__linux__) || defined(_AIX)1251&& (strcmp((char*)fontformat, "Type 1") != 0)1252&& !(isOpenJDK && (strcmp((char*)fontformat, "CFF") == 0))1253#endif1254) {1255continue;1256}1257result = (*FcPatternGetCharSet)(fontPattern,1258FC_CHARSET, 0, &charset);1259if (result != FcResultMatch) {1260free(family);1261free(fullname);1262free(styleStr);1263free(file);1264(*FcPatternDestroy)(pattern);1265(*FcFontSetDestroy)(fontset);1266closeFontConfig(libfontconfig, JNI_FALSE);1267return;1268}12691270/* We don't want 20 or 30 fonts, so once we hit 10 fonts,1271* then require that they really be adding value. Too many1272* adversely affects load time for minimal value-add.1273* This is still likely far more than we've had in the past.1274*/1275if (j==10) {1276minGlyphs = 50;1277}1278if (unionCharset == NULL) {1279unionCharset = charset;1280} else {1281if ((*FcCharSetSubtractCount)(charset, unionCharset)1282> minGlyphs) {1283unionCharset = (* FcCharSetUnion)(unionCharset, charset);1284} else {1285continue;1286}1287}12881289fontCount++; // found a font we will use.1290(*FcPatternGetString)(fontPattern, FC_FILE, 0, &file[j]);1291(*FcPatternGetString)(fontPattern, FC_FAMILY, 0, &family[j]);1292(*FcPatternGetString)(fontPattern, FC_STYLE, 0, &styleStr[j]);1293(*FcPatternGetString)(fontPattern, FC_FULLNAME, 0, &fullname[j]);1294if (!includeFallbacks) {1295break;1296}1297if (fontCount == 254) {1298break; // CompositeFont will only use up to 254 slots from here.1299}1300}13011302/* Once we get here 'fontCount' is the number of returned fonts1303* we actually want to use, so we create 'fcFontArr' of that length.1304* The non-null entries of "family[]" etc are those fonts.1305* Then loop again over all nfonts adding just those non-null ones1306* to 'fcFontArr'. If its null (we didn't want the font)1307* then we don't enter the main body.1308* So we should never get more than 'fontCount' entries.1309*/1310if (includeFallbacks) {1311fcFontArr =1312(*env)->NewObjectArray(env, fontCount, fcFontClass, NULL);1313if (IS_NULL(fcFontArr)) {1314free(family);1315free(fullname);1316free(styleStr);1317free(file);1318(*FcPatternDestroy)(pattern);1319(*FcFontSetDestroy)(fontset);1320closeFontConfig(libfontconfig, JNI_FALSE);1321return;1322}1323(*env)->SetObjectField(env,fcCompFontObj, fcAllFontsID, fcFontArr);1324}1325fn=0;13261327for (j=0;j<nfonts;j++) {1328if (family[j] != NULL) {1329jobject fcFont =1330(*env)->NewObject(env, fcFontClass, fcFontCons);1331if (IS_NULL(fcFont)) break;1332jstr = (*env)->NewStringUTF(env, (const char*)family[j]);1333if (IS_NULL(jstr)) break;1334(*env)->SetObjectField(env, fcFont, familyNameID, jstr);1335if (file[j] != NULL) {1336jstr = (*env)->NewStringUTF(env, (const char*)file[j]);1337if (IS_NULL(jstr)) break;1338(*env)->SetObjectField(env, fcFont, fontFileID, jstr);1339}1340if (styleStr[j] != NULL) {1341jstr = (*env)->NewStringUTF(env, (const char*)styleStr[j]);1342if (IS_NULL(jstr)) break;1343(*env)->SetObjectField(env, fcFont, styleNameID, jstr);1344}1345if (fullname[j] != NULL) {1346jstr = (*env)->NewStringUTF(env, (const char*)fullname[j]);1347if (IS_NULL(jstr)) break;1348(*env)->SetObjectField(env, fcFont, fullNameID, jstr);1349}1350if (fn==0) {1351(*env)->SetObjectField(env, fcCompFontObj,1352fcFirstFontID, fcFont);1353}1354if (includeFallbacks) {1355(*env)->SetObjectArrayElement(env, fcFontArr, fn++,fcFont);1356} else {1357break;1358}1359}1360}1361(*FcFontSetDestroy)(fontset);1362(*FcPatternDestroy)(pattern);1363free(family);1364free(styleStr);1365free(fullname);1366free(file);1367}13681369/* release resources and close the ".so" */13701371if (locale) {1372(*env)->ReleaseStringUTFChars (env, localeStr, (const char*)locale);1373}1374closeFontConfig(libfontconfig, JNI_TRUE);1375}137613771378