/* * Copyright (c) 1998, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions.
*/
staticchar **getX11FontPath ()
{ char **x11Path, **fontdirs; int i, pos, slen, nPaths, numDirs;
x11Path = XGetFontPath (awt_display, &nPaths);
/* This isn't ever going to be perfect: the font path may contain * much we aren't interested in, but the cost should be moderate * Exclude all directories that contain the strings "Speedo","/F3/", * "75dpi", "100dpi", "misc" or "bitmap", or don't begin with a "/", * the last of which should exclude font servers. * Also exclude the user specific ".gnome*" directories which * aren't going to contain the system fonts we need. * Hopefully we are left only with Type1 and TrueType directories. * It doesn't matter much if there are extraneous directories, it'll just * cost us a little wasted effort upstream.
*/
fontdirs = (char**)calloc(nPaths+1, sizeof(char*)); if (fontdirs == NULL) { return NULL;
}
pos = 0; for (i=0; i < nPaths; i++) { if (x11Path[i][0] != '/') { continue;
} if (strstr(x11Path[i], "/75dpi") != NULL) { continue;
} if (strstr(x11Path[i], "/100dpi") != NULL) { continue;
} if (strstr(x11Path[i], "/misc") != NULL) { continue;
} if (strstr(x11Path[i], "/Speedo") != NULL) { continue;
} if (strstr(x11Path[i], ".gnome") != NULL) { continue;
}
fontdirs[pos] = strdup(x11Path[i]);
slen = strlen(fontdirs[pos]); if (slen > 0 && fontdirs[pos][slen-1] == '/') {
fontdirs[pos][slen-1] = '\0'; /* null out trailing "/" */
}
pos++;
}
#ifdefined(__linux__) /* from awt_LoadLibrary.c */
JNIEXPORT jboolean JNICALL AWTIsHeadless(); #endif
/* This eliminates duplicates, at a non-linear but acceptable cost * since the lists are expected to be reasonably short, and then * deletes references to non-existent directories, and returns * a single path consisting of unique font directories.
*/ staticchar* mergePaths(char **p1, char **p2, char **p3, jboolean noType1) {
int len1=0, len2=0, len3=0, totalLen=0, numDirs=0,
currLen, i, j, found, pathLen=0; char **ptr, **fontdirs; char *fontPath = NULL;
if (p1 != NULL) {
ptr = p1; while (*ptr++ != NULL) len1++;
} if (p2 != NULL) {
ptr = p2;
while (*ptr++ != NULL) len2++;
} if (p3 != NULL) {
ptr = p3; while (*ptr++ != NULL) len3++;
}
totalLen = len1+len2+len3;
fontdirs = (char**)calloc(totalLen, sizeof(char*)); if (fontdirs == NULL) { return NULL;
}
for (i=0; i < len1; i++) { if (noType1 && strstr(p1[i], "Type1") != NULL) { continue;
}
fontdirs[numDirs++] = p1[i];
}
currLen = numDirs; /* only compare against previous path dirs */ for (i=0; i < len2; i++) { if (noType1 && strstr(p2[i], "Type1") != NULL) { continue;
}
found = 0; for (j=0; j < currLen; j++) { if (strcmp(fontdirs[j], p2[i]) == 0) {
found = 1; break;
}
} if (!found) {
fontdirs[numDirs++] = p2[i];
}
}
currLen = numDirs; /* only compare against previous path dirs */ for (i=0; i < len3; i++) { if (noType1 && strstr(p3[i], "Type1") != NULL) { continue;
}
found = 0; for (j=0; j < currLen; j++) { if (strcmp(fontdirs[j], p3[i]) == 0) {
found = 1; break;
}
} if (!found) {
fontdirs[numDirs++] = p3[i];
}
}
/* Now fontdirs contains unique dirs and numDirs records how many. * What we don't know is if they all exist. On reflection I think * this isn't an issue, so for now I will return all these locations,
* converted to one string */ for (i=0; i<numDirs; i++) {
pathLen += (strlen(fontdirs[i]) + 1);
} if (pathLen > 0 && (fontPath = malloc(pathLen))) {
*fontPath = '\0'; for (i = 0; i<numDirs; i++) { if (i != 0) {
strcat(fontPath, ":");
}
strcat(fontPath, fontdirs[i]);
}
}
free (fontdirs);
return fontPath;
}
/* * The goal of this function is to find all "system" fonts which * are needed by the JRE to display text in supported locales etc, and * to support APIs which allow users to enumerate all system fonts and use * them from their Java applications. * The preferred mechanism is now using the new "fontconfig" library * This exists on newer versions of Linux and Solaris (S10 and above) * The library is dynamically located. The results are merged with * a set of "known" locations and with the X11 font path, if running in * a local X11 environment. * The hardwired paths are built into the JDK binary so as new font locations * are created on a host platform for them to be located by the JRE they will * need to be added ito the host's font configuration database, typically * /etc/fonts/local.conf, and to ensure that directory contains a fonts.dir * NB: Fontconfig also depends heavily for performance on the host O/S * maintaining up to date caches. * This is consistent with the requirements of the desktop environments * on these OSes. * This also frees us from X11 APIs as JRE is required to function in * a "headless" mode where there is no Xserver.
*/ staticchar *getPlatformFontPathChars(JNIEnv *env, jboolean noType1, jboolean isX11) {
/* As of 1.5 we try to use fontconfig on both Solaris and Linux. * If its not available NULL is returned.
*/
fcdirs = getFontConfigLocations();
#ifdefined(__linux__)
knowndirs = fullLinuxFontPath; #elifdefined(_AIX)
knowndirs = fullAixFontPath; #endif /* REMIND: this code requires to be executed when the GraphicsEnvironment * is already initialised. That is always true, but if it were not so, * this code could throw an exception and the fontpath would fail to * be initialised.
*/ #ifndef HEADLESS if (isX11) { // The following only works in an x11 environment. #ifdefined(__linux__) /* There's no headless build on linux ... */ if (!AWTIsHeadless()) { /* .. so need to call a function to check */ #endif /* Using the X11 font path to locate font files is now a fallback * useful only if fontconfig failed, or is incomplete. So we could * remove this code completely and the consequences should be rare * and non-fatal. If this happens, then the calling Java code can * be modified to no longer require that the AWT lock (the X11GE) * be initialised prior to calling this code.
*/
AWT_LOCK(); if (isDisplayLocal(env)) {
x11dirs = getX11FontPath();
}
AWT_UNLOCK(); #ifdefined(__linux__)
} #endif
} #endif/* !HEADLESS */
path = mergePaths(fcdirs, x11dirs, knowndirs, noType1); if (fcdirs != NULL) { char **p = fcdirs; while (*p != NULL) free(*p++);
free(fcdirs);
}
if (x11dirs != NULL) { char **p = x11dirs; while (*p != NULL) free(*p++);
free(x11dirs);
}
if (ptr == NULL) {
ptr = getPlatformFontPathChars(env, noType1, isX11);
}
ret = (*env)->NewStringUTF(env, ptr); return ret;
}
#include <dlfcn.h>
#include <fontconfig/fontconfig.h>
staticvoid* openFontConfig() {
char *homeEnv; staticchar *homeEnvStr = "HOME="; /* must be static */ void* libfontconfig = NULL;
/* Private workaround to not use fontconfig library. * May be useful during testing/debugging
*/ char *useFC = getenv("USE_J2D_FONTCONFIG"); if (useFC != NULL && !strcmp(useFC, "no")) { return NULL;
}
#ifdefined(_AIX) /* On AIX, fontconfig is not a standard package supported by IBM. * instead it has to be installed from the "AIX Toolbox for Linux Applications" * site http://www-03.ibm.com/systems/power/software/aix/linux/toolbox/alpha.html * and will be installed under /opt/freeware/lib/libfontconfig.a. * Notice that the archive contains the real 32- and 64-bit shared libraries. * We first try to load 'libfontconfig.so' from the default library path in the * case the user has installed a private version of the library and if that * doesn't succeed, we try the version from /opt/freeware/lib/libfontconfig.a
*/
libfontconfig = dlopen("libfontconfig.so", RTLD_LOCAL|RTLD_LAZY); if (libfontconfig == NULL) {
libfontconfig = dlopen("/opt/freeware/lib/libfontconfig.a(libfontconfig.so.1)", RTLD_MEMBER|RTLD_LOCAL|RTLD_LAZY); if (libfontconfig == NULL) { return NULL;
}
} #else /* 64 bit sparc should pick up the right version from the lib path. * New features may be added to libfontconfig, this is expected to * be compatible with old features, but we may need to start * distinguishing the library version, to know whether to expect * certain symbols - and functionality - to be available. * Also add explicit search for .so.1 in case .so symlink doesn't exist.
*/
libfontconfig = dlopen(FONTCONFIG_DLL_VERSIONED, RTLD_LOCAL|RTLD_LAZY); if (libfontconfig == NULL) {
libfontconfig = dlopen(FONTCONFIG_DLL, RTLD_LOCAL|RTLD_LAZY); if (libfontconfig == NULL) { return NULL;
}
} #endif
/* Version 1.0 of libfontconfig crashes if HOME isn't defined in * the environment. This should generally never happen, but we can't * control it, and can't control the version of fontconfig, so iff * its not defined we set it to an empty value which is sufficient * to prevent a crash. I considered unsetting it before exit, but * it doesn't appear to work on Solaris, so I will leave it set.
*/
homeEnv = getenv("HOME"); if (homeEnv == NULL) {
putenv(homeEnvStr);
}
/* NB FcFini is not in (eg) the Solaris 10 version of fontconfig. Its not * clear if this means we are really leaking resources in those cases * but it seems we should call this function when its available. * But since the Swing GTK code may be still accessing the lib, its probably * safest for now to just let this "leak" rather than potentially * concurrently free global data still in use by other code.
*/ #if 0 if (fcFini) { /* release resources */
FcFiniFuncType FcFini = (FcFiniFuncType)dlsym(libfontconfig, "FcFini");
/* Make calls into the fontconfig library to build a search for * outline fonts, and to get the set of full file paths from the matches. * This set is returned from the call to FcFontList(..) * We allocate an array of char* pointers sufficient to hold all * the matches + 1 extra which ensures there will be a NULL after all * valid entries. * We call FcStrDirname strip the file name from the path, and * check if we have yet seen this directory. If not we add a pointer to * it into our array of char*. Note that FcStrDirname returns newly * allocated storage so we can use this in the return char** value. * Finally we clean up, freeing allocated resources, and return the * array of unique directories.
*/
pattern = (*FcPatternBuild)(NULL, FC_OUTLINE, FcTypeBool, FcTrue, NULL);
objset = (*FcObjectSetBuild)(FC_FILE, NULL);
fontSet = (*FcFontList)(NULL, pattern, objset); if (fontSet == NULL) { /* FcFontList() may return NULL if fonts are not installed. */
fontdirs = NULL;
} else {
fontdirs = (char**)calloc(fontSet->nfont+1, sizeof(char*)); if (fontdirs == NULL) {
(*FcFontSetDestroy)(fontSet); goto cleanup;
} for (f=0; f < fontSet->nfont; f++) {
FcChar8 *file;
FcChar8 *dir; if ((*FcPatternGetString)(fontSet->fonts[f], FC_FILE, 0, &file) ==
FcResultMatch) {
dir = (*FcStrDirname)(file);
found = 0; for (i=0;i<numdirs; i++) { if (strcmp(fontdirs[i], (char*)dir) == 0) {
found = 1; break;
}
} if (!found) {
fontdirs[numdirs++] = (char*)dir;
} else {
free((char*)dir);
}
}
} /* Free fontset if one was returned */
(*FcFontSetDestroy)(fontSet);
}
cleanup: /* Free memory and close the ".so" */
(*FcObjectSetDestroy)(objset);
(*FcPatternDestroy)(pattern);
closeFontConfig(libfontconfig, JNI_TRUE); return fontdirs;
}
/* These are copied from sun.awt.SunHints. * Consider initialising them as ints using JNI for more robustness.
*/ #define TEXT_AA_OFF 1 #define TEXT_AA_ON 2 #define TEXT_AA_LCD_HRGB 4 #define TEXT_AA_LCD_HBGR 5 #define TEXT_AA_LCD_VRGB 6 #define TEXT_AA_LCD_VBGR 7
pattern = (*FcNameParse)((FcChar8 *)fcName); if (locale != NULL) {
(*FcPatternAddString)(pattern, FC_LANG, (unsignedchar*)locale);
}
(*FcConfigSubstitute)(NULL, pattern, FcMatchPattern);
(*FcDefaultSubstitute)(pattern);
matchPattern = (*FcFontMatch)(NULL, pattern, &result); /* Perhaps should call FcFontRenderPrepare() here as some pattern * elements might change as a result of that call, but I'm not seeing * any difference in testing.
*/ if (matchPattern) {
(*FcPatternGetBool)(matchPattern, FC_ANTIALIAS, 0, &antialias);
(*FcPatternGetInteger)(matchPattern, FC_RGBA, 0, &rgba);
(*FcPatternDestroy)(matchPattern);
}
(*FcPatternDestroy)(pattern);
/* Optionally get the cache dir locations. This isn't * available until v 2.4.x, but this is OK since on those later versions * we can check the time stamps on the cache dirs to see if we * are out of date. There are a couple of assumptions here. First * that the time stamp on the directory changes when the contents are * updated. Secondly that the locations don't change. The latter is * most likely if a new version of fontconfig is installed, but we also * invalidate the cache if we detect that. Arguably even that is "rare", * and most likely is tied to an OS upgrade which gets a new file anyway.
*/
FcConfigGetCacheDirs =
(FcConfigGetCacheDirsFuncType)dlsym(libfontconfig, "FcConfigGetCacheDirs");
FcStrListNext =
(FcStrListNextFuncType)dlsym(libfontconfig, "FcStrListNext");
FcStrListDone =
(FcStrListDoneFuncType)dlsym(libfontconfig, "FcStrListDone"); if (FcStrListNext != NULL && FcStrListDone != NULL &&
FcConfigGetCacheDirs != NULL) {
FcStrList* cacheDirs;
FcChar8* cacheDir; int cnt = 0;
jobject cacheDirArray =
(*env)->GetObjectField(env, fcInfoObj, fcCacheDirsID); int max = (*env)->GetArrayLength(env, cacheDirArray);
/* locale may not usually be necessary as fontconfig appears to apply * this anyway based on the user's environment. However we want * to use the value of the JDK startup locale so this should take * care of it.
*/ if (locale != NULL) {
(*FcPatternAddString)(pattern, FC_LANG, (unsignedchar*)locale);
}
(*FcConfigSubstitute)(NULL, pattern, FcMatchPattern);
(*FcDefaultSubstitute)(pattern);
fontset = (*FcFontSort)(NULL, pattern, FcTrue, NULL, &result); if (fontset == NULL) {
(*FcPatternDestroy)(pattern);
closeFontConfig(libfontconfig, JNI_FALSE); if (locale) {
(*env)->ReleaseStringUTFChars(env, localeStr, (constchar*)locale);
} return;
}
/* fontconfig returned us "nfonts". If we are just getting the * first font, we set nfont to zero. Otherwise we use "nfonts". * Next create separate C arrays of length nfonts for family file etc. * Inspect the returned fonts and the ones we like (adds enough glyphs) * are added to the arrays and we increment 'fontCount'.
*/
nfonts = fontset->nfont;
family = (FcChar8**)calloc(nfonts, sizeof(FcChar8*));
styleStr = (FcChar8**)calloc(nfonts, sizeof(FcChar8*));
fullname = (FcChar8**)calloc(nfonts, sizeof(FcChar8*));
file = (FcChar8**)calloc(nfonts, sizeof(FcChar8*)); if (family == NULL || styleStr == NULL ||
fullname == NULL || file == NULL) { if (family != NULL) {
free(family);
} if (styleStr != NULL) {
free(styleStr);
} if (fullname != NULL) {
free(fullname);
} if (file != NULL) {
free(file);
}
(*FcPatternDestroy)(pattern);
(*FcFontSetDestroy)(fontset);
closeFontConfig(libfontconfig, JNI_FALSE); if (locale) {
(*env)->ReleaseStringUTFChars(env, localeStr, (constchar*)locale);
} return;
}
fontCount = 0;
minGlyphs = 20; if (debugMinGlyphsStr != NULL) { int val = minGlyphs;
sscanf(debugMinGlyphsStr, "%5d", &val); if (val >= 0 && val <= 65536) {
minGlyphs = val;
}
}
fontformat = NULL;
(*FcPatternGetString)(fontPattern, FC_FONTFORMAT, 0, &fontformat); /* We only want TrueType fonts but some Linuxes still depend * on Type 1 fonts for some Locale support, so we'll allow * them there.
*/ if (fontformat != NULL
&& (strcmp((char*)fontformat, "TrueType") != 0) #ifdefined(__linux__) || defined(_AIX)
&& (strcmp((char*)fontformat, "Type 1") != 0)
&& (strcmp((char*)fontformat, "CFF") != 0) #endif
) { continue;
}
result = (*FcPatternGetCharSet)(fontPattern,
FC_CHARSET, 0, &charset); if (result != FcResultMatch) {
free(family);
free(fullname);
free(styleStr);
free(file);
(*FcPatternDestroy)(pattern);
(*FcFontSetDestroy)(fontset); if (prevUnionCharset != NULL) {
(*FcCharSetDestroy)(prevUnionCharset);
}
closeFontConfig(libfontconfig, JNI_FALSE); if (locale) {
(*env)->ReleaseStringUTFChars(env, localeStr, (constchar*)locale);
} return;
}
/* We don't want 20 or 30 fonts, so once we hit 10 fonts, * then require that they really be adding value. Too many * adversely affects load time for minimal value-add. * This is still likely far more than we've had in the past.
*/ if (j==10) {
minGlyphs = 50;
} if (unionCharset == NULL) {
unionCharset = charset;
} else { if ((*FcCharSetSubtractCount)(charset, unionCharset)
> minGlyphs) {
unionCharset = (* FcCharSetUnion)(unionCharset, charset); if (prevUnionCharset != NULL) {
(*FcCharSetDestroy)(prevUnionCharset);
}
prevUnionCharset = unionCharset;
} else { continue;
}
}
fontCount++; // found a font we will use.
(*FcPatternGetString)(fontPattern, FC_FILE, 0, &file[j]);
(*FcPatternGetString)(fontPattern, FC_FAMILY, 0, &family[j]);
(*FcPatternGetString)(fontPattern, FC_STYLE, 0, &styleStr[j]);
(*FcPatternGetString)(fontPattern, FC_FULLNAME, 0, &fullname[j]); if (!includeFallbacks) { break;
} if (fontCount == 254) { break; // CompositeFont will only use up to 254 slots from here.
}
}
// Release last instance of CharSet union if (prevUnionCharset != NULL) {
(*FcCharSetDestroy)(prevUnionCharset);
}
/* Once we get here 'fontCount' is the number of returned fonts * we actually want to use, so we create 'fcFontArr' of that length. * The non-null entries of "family[]" etc are those fonts. * Then loop again over all nfonts adding just those non-null ones * to 'fcFontArr'. If its null (we didn't want the font) * then we don't enter the main body. * So we should never get more than 'fontCount' entries.
*/ if (includeFallbacks) {
fcFontArr =
(*env)->NewObjectArray(env, fontCount, fcFontClass, NULL); if (IS_NULL(fcFontArr)) {
free(family);
free(fullname);
free(styleStr);
free(file);
(*FcPatternDestroy)(pattern);
(*FcFontSetDestroy)(fontset);
closeFontConfig(libfontconfig, JNI_FALSE); if (locale) {
(*env)->ReleaseStringUTFChars(env, localeStr, (constchar*)locale);
} return;
}
(*env)->SetObjectField(env,fcCompFontObj, fcAllFontsID, fcFontArr);
}
fn=0;
for (j=0;j<nfonts;j++) { if (family[j] != NULL) {
jobject fcFont =
(*env)->NewObject(env, fcFontClass, fcFontCons); if (IS_NULL(fcFont)) break;
jstr = (*env)->NewStringUTF(env, (constchar*)family[j]); if (IS_NULL(jstr)) break;
(*env)->SetObjectField(env, fcFont, familyNameID, jstr);
(*env)->DeleteLocalRef(env, jstr); if (file[j] != NULL) {
jstr = (*env)->NewStringUTF(env, (constchar*)file[j]); if (IS_NULL(jstr)) break;
(*env)->SetObjectField(env, fcFont, fontFileID, jstr);
(*env)->DeleteLocalRef(env, jstr);
} if (styleStr[j] != NULL) {
jstr = (*env)->NewStringUTF(env, (constchar*)styleStr[j]); if (IS_NULL(jstr)) break;
(*env)->SetObjectField(env, fcFont, styleNameID, jstr);
(*env)->DeleteLocalRef(env, jstr);
} if (fullname[j] != NULL) {
jstr = (*env)->NewStringUTF(env, (constchar*)fullname[j]); if (IS_NULL(jstr)) break;
(*env)->SetObjectField(env, fcFont, fullNameID, jstr);
(*env)->DeleteLocalRef(env, jstr);
} if (fn==0) {
(*env)->SetObjectField(env, fcCompFontObj,
fcFirstFontID, fcFont);
} if (includeFallbacks) {
(*env)->SetObjectArrayElement(env, fcFontArr, fn++,fcFont);
} else {
(*env)->DeleteLocalRef(env, fcFont); break;
}
(*env)->DeleteLocalRef(env, fcFont);
}
} if (includeFallbacks) {
(*env)->DeleteLocalRef(env, fcFontArr);
}
(*env)->DeleteLocalRef(env, fcCompFontObj);
(*FcFontSetDestroy)(fontset);
(*FcPatternDestroy)(pattern);
free(family);
free(styleStr);
free(fullname);
free(file);
}
/* release resources and close the ".so" */
if (locale) {
(*env)->ReleaseStringUTFChars(env, localeStr, (constchar*)locale);
}
closeFontConfig(libfontconfig, JNI_TRUE);
}
¤ Dauer der Verarbeitung: 0.22 Sekunden
(vorverarbeitet)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.