Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/solaris/classes/sun/font/FontConfigManager.java
32287 views
/*1* Copyright (c) 2008, 2013, 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*/2425package sun.font;2627import java.util.Locale;2829import sun.awt.SunHints;30import sun.awt.SunToolkit;31import sun.util.logging.PlatformLogger;3233/**34* Small utility class to manage FontConfig.35*/36public class FontConfigManager {3738static boolean fontConfigFailed = false;3940/* This is populated by native */41private static final FontConfigInfo fcInfo = new FontConfigInfo();4243/* Begin support for GTK Look and Feel - query libfontconfig and44* return a composite Font to Swing that uses the desktop font(s).45*/4647/* These next three classes are just data structures.48*/49public static class FontConfigFont {50public String familyName; // eg Bitstream Vera Sans51public String styleStr; // eg Bold52public String fullName; // eg Bitstream Vera Sans Bold53public String fontFile; // eg /usr/X11/lib/fonts/foo.ttf54}5556public static class FcCompFont {57public String fcName; // eg sans58public String fcFamily; // eg sans59public String jdkName; // eg sansserif60public int style; // eg 0=PLAIN61public FontConfigFont firstFont;62public FontConfigFont[] allFonts;63//boolean preferBitmaps; // if embedded bitmaps preferred over AA64public CompositeFont compFont; // null if not yet created/known.65}6667public static class FontConfigInfo {68public int fcVersion;69public String[] cacheDirs = new String[4];70}7172/* fontconfig recognises slants roman, italic, as well as oblique,73* and a slew of weights, where the ones that matter here are74* regular and bold.75* To fully qualify what we want, we can for example ask for (eg)76* Font.PLAIN : "serif:regular:roman"77* Font.BOLD : "serif:bold:roman"78* Font.ITALIC : "serif:regular:italic"79* Font.BOLD|Font.ITALIC : "serif:bold:italic"80*/81private static String[] fontConfigNames = {82"sans:regular:roman",83"sans:bold:roman",84"sans:regular:italic",85"sans:bold:italic",8687"serif:regular:roman",88"serif:bold:roman",89"serif:regular:italic",90"serif:bold:italic",9192"monospace:regular:roman",93"monospace:bold:roman",94"monospace:regular:italic",95"monospace:bold:italic",96};9798/* This array has the array elements created in Java code and is99* passed down to native to be filled in.100*/101private FcCompFont[] fontConfigFonts;102103/**104* Instantiates a new FontConfigManager getting the default instance105* of FontManager from the FontManagerFactory.106*/107public FontConfigManager() {108}109110/* Called from code that needs to know what are the AA settings111* that apps using FC would pick up for the default desktop font.112* Note apps can change the default desktop font. etc, so this113* isn't certain to be right but its going to correct for most cases.114* Native return values map to the text aa values in sun.awt.SunHints.115* which is used to look up the renderinghint value object.116*/117public static Object getFontConfigAAHint() {118return getFontConfigAAHint("sans");119}120121/* This is public solely so that for debugging purposes it can be called122* with other names, which might (eg) include a size, eg "sans-24"123* The return value is a text aa rendering hint value.124* Normally we should call the no-args version.125*/126public static Object getFontConfigAAHint(String fcFamily) {127if (FontUtilities.isWindows) {128return null;129} else {130int hint = getFontConfigAASettings(getFCLocaleStr(), fcFamily);131if (hint < 0) {132return null;133} else {134return SunHints.Value.get(SunHints.INTKEY_TEXT_ANTIALIASING,135hint);136}137}138}139140141private static String getFCLocaleStr() {142Locale l = SunToolkit.getStartupLocale();143String localeStr = l.getLanguage();144String country = l.getCountry();145if (!country.equals("")) {146localeStr = localeStr + "-" + country;147}148return localeStr;149}150151/* This does cause the native libfontconfig to be loaded and unloaded,152* but it does not incur the overhead of initialisation of its153* data structures, so shouldn't have a measurable impact.154*/155public static native int getFontConfigVersion();156157/* This can be made public if it's needed to force a re-read158* rather than using the cached values. The re-read would be needed159* only if some event signalled that the fontconfig has changed.160* In that event this method would need to return directly the array161* to be used by the caller in case it subsequently changed.162*/163public synchronized void initFontConfigFonts(boolean includeFallbacks) {164165if (fontConfigFonts != null) {166if (!includeFallbacks || (fontConfigFonts[0].allFonts != null)) {167return;168}169}170171if (FontUtilities.isWindows || fontConfigFailed) {172return;173}174175long t0 = 0;176if (FontUtilities.isLogging()) {177t0 = System.nanoTime();178}179180FcCompFont[] fontArr = new FcCompFont[fontConfigNames.length];181182for (int i = 0; i< fontArr.length; i++) {183fontArr[i] = new FcCompFont();184fontArr[i].fcName = fontConfigNames[i];185int colonPos = fontArr[i].fcName.indexOf(':');186fontArr[i].fcFamily = fontArr[i].fcName.substring(0, colonPos);187fontArr[i].jdkName = FontUtilities.mapFcName(fontArr[i].fcFamily);188fontArr[i].style = i % 4; // depends on array order.189}190getFontConfig(getFCLocaleStr(), fcInfo, fontArr, includeFallbacks);191FontConfigFont anyFont = null;192/* If don't find anything (eg no libfontconfig), then just return */193for (int i = 0; i< fontArr.length; i++) {194FcCompFont fci = fontArr[i];195if (fci.firstFont == null) {196if (FontUtilities.isLogging()) {197PlatformLogger logger = FontUtilities.getLogger();198logger.info("Fontconfig returned no font for " +199fontArr[i].fcName);200}201fontConfigFailed = true;202} else if (anyFont == null) {203anyFont = fci.firstFont;204}205}206207if (anyFont == null) {208if (FontUtilities.isLogging()) {209PlatformLogger logger = FontUtilities.getLogger();210logger.info("Fontconfig returned no fonts at all.");211}212fontConfigFailed = true;213return;214} else if (fontConfigFailed) {215for (int i = 0; i< fontArr.length; i++) {216if (fontArr[i].firstFont == null) {217fontArr[i].firstFont = anyFont;218}219}220}221222fontConfigFonts = fontArr;223224if (FontUtilities.isLogging()) {225226PlatformLogger logger = FontUtilities.getLogger();227228long t1 = System.nanoTime();229logger.info("Time spent accessing fontconfig="230+ ((t1 - t0) / 1000000) + "ms.");231232for (int i = 0; i< fontConfigFonts.length; i++) {233FcCompFont fci = fontConfigFonts[i];234logger.info("FC font " + fci.fcName+" maps to family " +235fci.firstFont.familyName +236" in file " + fci.firstFont.fontFile);237if (fci.allFonts != null) {238for (int f=0;f<fci.allFonts.length;f++) {239FontConfigFont fcf = fci.allFonts[f];240logger.info("Family=" + fcf.familyName +241" Style="+ fcf.styleStr +242" Fullname="+fcf.fullName +243" File="+fcf.fontFile);244}245}246}247}248}249250public PhysicalFont registerFromFcInfo(FcCompFont fcInfo) {251252SunFontManager fm = SunFontManager.getInstance();253254/* If it's a TTC file we need to know that as we will need to255* make sure we return the right font */256String fontFile = fcInfo.firstFont.fontFile;257int offset = fontFile.length()-4;258if (offset <= 0) {259return null;260}261String ext = fontFile.substring(offset).toLowerCase();262boolean isTTC = ext.equals(".ttc");263264/* If this file is already registered, can just return its font.265* However we do need to check in case it's a TTC as we need266* a specific font, so rather than directly returning it, let267* findFont2D resolve that.268*/269PhysicalFont physFont = fm.getRegisteredFontFile(fontFile);270if (physFont != null) {271if (isTTC) {272Font2D f2d = fm.findFont2D(fcInfo.firstFont.familyName,273fcInfo.style,274FontManager.NO_FALLBACK);275if (f2d instanceof PhysicalFont) { /* paranoia */276return (PhysicalFont)f2d;277} else {278return null;279}280} else {281return physFont;282}283}284285/* If the font may hide a JRE font (eg fontconfig says it is286* Lucida Sans), we want to use the JRE version, so make it287* point to the JRE font.288*/289physFont = fm.findJREDeferredFont(fcInfo.firstFont.familyName,290fcInfo.style);291292/* It is also possible the font file is on the "deferred" list,293* in which case we can just initialise it now.294*/295if (physFont == null &&296fm.isDeferredFont(fontFile) == true) {297physFont = fm.initialiseDeferredFont(fcInfo.firstFont.fontFile);298/* use findFont2D to get the right font from TTC's */299if (physFont != null) {300if (isTTC) {301Font2D f2d = fm.findFont2D(fcInfo.firstFont.familyName,302fcInfo.style,303FontManager.NO_FALLBACK);304if (f2d instanceof PhysicalFont) { /* paranoia */305return (PhysicalFont)f2d;306} else {307return null;308}309} else {310return physFont;311}312}313}314315/* In the majority of cases we reach here, and need to determine316* the type and rank to register the font.317*/318if (physFont == null) {319int fontFormat = SunFontManager.FONTFORMAT_NONE;320int fontRank = Font2D.UNKNOWN_RANK;321322if (ext.equals(".ttf") || isTTC) {323fontFormat = SunFontManager.FONTFORMAT_TRUETYPE;324fontRank = Font2D.TTF_RANK;325} else if (ext.equals(".pfa") || ext.equals(".pfb")) {326fontFormat = SunFontManager.FONTFORMAT_TYPE1;327fontRank = Font2D.TYPE1_RANK;328}329physFont = fm.registerFontFile(fcInfo.firstFont.fontFile, null,330fontFormat, true, fontRank);331}332return physFont;333}334335/*336* We need to return a Composite font which has as the font in337* its first slot one obtained from fontconfig.338*/339public CompositeFont getFontConfigFont(String name, int style) {340341name = name.toLowerCase();342343initFontConfigFonts(false);344if (fontConfigFonts == null) {345// This avoids an immediate NPE if fontconfig look up failed346// but doesn't guarantee this is a recoverable situation.347return null;348}349350FcCompFont fcInfo = null;351for (int i=0; i<fontConfigFonts.length; i++) {352if (name.equals(fontConfigFonts[i].fcFamily) &&353style == fontConfigFonts[i].style) {354fcInfo = fontConfigFonts[i];355break;356}357}358if (fcInfo == null) {359fcInfo = fontConfigFonts[0];360}361362if (FontUtilities.isLogging()) {363FontUtilities.getLogger()364.info("FC name=" + name + " style=" + style +365" uses " + fcInfo.firstFont.familyName +366" in file: " + fcInfo.firstFont.fontFile);367}368369if (fcInfo.compFont != null) {370return fcInfo.compFont;371}372373/* jdkFont is going to be used for slots 1..N and as a fallback.374* Slot 0 will be the physical font from fontconfig.375*/376FontManager fm = FontManagerFactory.getInstance();377CompositeFont jdkFont = (CompositeFont)378fm.findFont2D(fcInfo.jdkName, style, FontManager.LOGICAL_FALLBACK);379380if (fcInfo.firstFont.familyName == null ||381fcInfo.firstFont.fontFile == null) {382return (fcInfo.compFont = jdkFont);383}384385/* First, see if the family and exact style is already registered.386* If it is, use it. If it's not, then try to register it.387* If that registration fails (signalled by null) just return the388* regular JDK composite.389* Algorithmically styled fonts won't match on exact style, so390* will fall through this code, but the regisration code will391* find that file already registered and return its font.392*/393FontFamily family = FontFamily.getFamily(fcInfo.firstFont.familyName);394PhysicalFont physFont = null;395if (family != null) {396Font2D f2D = family.getFontWithExactStyleMatch(fcInfo.style);397if (f2D instanceof PhysicalFont) {398physFont = (PhysicalFont)f2D;399}400}401402if (physFont == null ||403!fcInfo.firstFont.fontFile.equals(physFont.platName)) {404physFont = registerFromFcInfo(fcInfo);405if (physFont == null) {406return (fcInfo.compFont = jdkFont);407}408family = FontFamily.getFamily(physFont.getFamilyName(null));409}410411/* Now register the fonts in the family (the other styles) after412* checking that they aren't already registered and are actually in413* a different file. They may be the same file in CJK cases.414* For cases where they are different font files - eg as is common for415* Latin fonts, then we rely on fontconfig to report these correctly.416* Assume that all styles of this font are found by fontconfig,417* so we can find all the family members which must be registered418* together to prevent synthetic styling.419*/420for (int i=0; i<fontConfigFonts.length; i++) {421FcCompFont fc = fontConfigFonts[i];422if (fc != fcInfo &&423physFont.getFamilyName(null).equals(fc.firstFont.familyName) &&424!fc.firstFont.fontFile.equals(physFont.platName) &&425family.getFontWithExactStyleMatch(fc.style) == null) {426427registerFromFcInfo(fontConfigFonts[i]);428}429}430431/* Now we have a physical font. We will back this up with the JDK432* logical font (sansserif, serif, or monospaced) that corresponds433* to the Pango/GTK/FC logical font name.434*/435return (fcInfo.compFont = new CompositeFont(physFont, jdkFont));436}437438/**439*440* @param locale441* @param fcFamily442* @return443*/444public FcCompFont[] getFontConfigFonts() {445return fontConfigFonts;446}447448/* Return an array of FcCompFont structs describing the primary449* font located for each of fontconfig/GTK/Pango's logical font names.450*/451private static native void getFontConfig(String locale,452FontConfigInfo fcInfo,453FcCompFont[] fonts,454boolean includeFallbacks);455456void populateFontConfig(FcCompFont[] fcInfo) {457fontConfigFonts = fcInfo;458}459460FcCompFont[] loadFontConfig() {461initFontConfigFonts(true);462return fontConfigFonts;463}464465FontConfigInfo getFontConfigInfo() {466initFontConfigFonts(true);467return fcInfo;468}469470private static native int471getFontConfigAASettings(String locale, String fcFamily);472}473474475