Path: blob/master/src/java.desktop/share/classes/sun/awt/FontConfiguration.java
41152 views
/*1* Copyright (c) 1996, 2021, 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.awt;2627import java.awt.Font;28import java.io.DataInputStream;29import java.io.DataOutputStream;30import java.io.File;31import java.io.FileInputStream;32import java.io.InputStream;33import java.io.IOException;34import java.io.OutputStream;35import java.nio.charset.Charset;36import java.nio.charset.CharsetEncoder;37import java.security.AccessController;38import java.security.PrivilegedAction;39import java.util.Arrays;40import java.util.HashMap;41import java.util.HashSet;42import java.util.Hashtable;43import java.util.Locale;44import java.util.Map.Entry;45import java.util.Properties;46import java.util.Set;47import java.util.Vector;48import sun.font.CompositeFontDescriptor;49import sun.font.SunFontManager;50import sun.font.FontManagerFactory;51import sun.font.FontUtilities;52import sun.util.logging.PlatformLogger;5354/**55* Provides the definitions of the five logical fonts: Serif, SansSerif,56* Monospaced, Dialog, and DialogInput. The necessary information57* is obtained from fontconfig files.58*/59public abstract class FontConfiguration {6061//static global runtime env62protected static String osVersion;63protected static String osName;64protected static String encoding; // canonical name of default nio charset65protected static Locale startupLocale = null;66protected static Hashtable<String, String> localeMap = null;67private static FontConfiguration fontConfig;68private static PlatformLogger logger;69protected static boolean isProperties = true;7071protected SunFontManager fontManager;72protected boolean preferLocaleFonts;73protected boolean preferPropFonts;7475private File fontConfigFile;76private boolean foundOsSpecificFile;77private boolean inited;78private String javaLib;7980/* A default FontConfiguration must be created before an alternate81* one to ensure proper static initialisation takes place.82*/83public FontConfiguration(SunFontManager fm) {84if (FontUtilities.debugFonts()) {85FontUtilities.logInfo("Creating standard Font Configuration");86}87if (FontUtilities.debugFonts() && logger == null) {88logger = PlatformLogger.getLogger("sun.awt.FontConfiguration");89}90fontManager = fm;91setOsNameAndVersion(); /* static initialization */92setEncoding(); /* static initialization */93/* Separating out the file location from the rest of the94* initialisation, so the caller has the option of doing95* something else if a suitable file isn't found.96*/97findFontConfigFile();98}99100public synchronized boolean init() {101if (!inited) {102this.preferLocaleFonts = false;103this.preferPropFonts = false;104setFontConfiguration();105readFontConfigFile(fontConfigFile);106initFontConfig();107inited = true;108}109return true;110}111112public FontConfiguration(SunFontManager fm,113boolean preferLocaleFonts,114boolean preferPropFonts) {115fontManager = fm;116if (FontUtilities.debugFonts()) {117FontUtilities.logInfo("Creating alternate Font Configuration");118}119this.preferLocaleFonts = preferLocaleFonts;120this.preferPropFonts = preferPropFonts;121/* fontConfig should be initialised by default constructor, and122* its data tables can be shared, since readFontConfigFile doesn't123* update any other state. Also avoid a doPrivileged block.124*/125initFontConfig();126}127128/**129* Fills in this instance's osVersion and osName members. By130* default uses the system properties os.name and os.version;131* subclasses may override.132*/133protected void setOsNameAndVersion() {134osName = System.getProperty("os.name");135osVersion = System.getProperty("os.version");136}137138private void setEncoding() {139encoding = Charset.defaultCharset().name();140startupLocale = SunToolkit.getStartupLocale();141}142143/////////////////////////////////////////////////////////////////////144// methods for loading the FontConfig file //145/////////////////////////////////////////////////////////////////////146147public boolean foundOsSpecificFile() {148return foundOsSpecificFile;149}150151/* Smoke test to see if we can trust this configuration by testing if152* the first slot of a composite font maps to an installed file.153*/154public boolean fontFilesArePresent() {155init();156short fontNameID = compFontNameIDs[0][0][0];157short fileNameID = getComponentFileID(fontNameID);158final String fileName = mapFileName(getComponentFileName(fileNameID));159@SuppressWarnings("removal")160Boolean exists = java.security.AccessController.doPrivileged(161new java.security.PrivilegedAction<Boolean>() {162public Boolean run() {163try {164File f = new File(fileName);165return Boolean.valueOf(f.exists());166}167catch (Exception e) {168return Boolean.FALSE;169}170}171});172return exists.booleanValue();173}174175private void findFontConfigFile() {176177foundOsSpecificFile = true; // default assumption.178String javaHome = System.getProperty("java.home");179if (javaHome == null) {180throw new Error("java.home property not set");181}182javaLib = javaHome + File.separator + "lib";183String javaConfFonts = javaHome +184File.separator + "conf" +185File.separator + "fonts";186String userConfigFile = System.getProperty("sun.awt.fontconfig");187if (userConfigFile != null) {188fontConfigFile = new File(userConfigFile);189} else {190fontConfigFile = findFontConfigFile(javaConfFonts);191if (fontConfigFile == null) {192fontConfigFile = findFontConfigFile(javaLib);193}194}195}196197private void readFontConfigFile(File f) {198/* This is invoked here as readFontConfigFile is only invoked199* once per VM, and always in a privileged context, thus the200* directory containing installed fall back fonts is accessed201* from this context202*/203getInstalledFallbackFonts(javaLib);204205if (f != null) {206try {207FileInputStream in = new FileInputStream(f.getPath());208if (isProperties) {209loadProperties(in);210} else {211loadBinary(in);212}213in.close();214if (FontUtilities.debugFonts()) {215logger.config("Read logical font configuration from " + f);216}217} catch (IOException e) {218if (FontUtilities.debugFonts()) {219logger.config("Failed to read logical font configuration from " + f);220}221}222}223String version = getVersion();224if (!"1".equals(version) && FontUtilities.debugFonts()) {225logger.config("Unsupported fontconfig version: " + version);226}227}228229protected void getInstalledFallbackFonts(String javaLib) {230String fallbackDirName = javaLib + File.separator +231"fonts" + File.separator + "fallback";232233File fallbackDir = new File(fallbackDirName);234if (fallbackDir.exists() && fallbackDir.isDirectory()) {235String[] ttfs = fallbackDir.list(fontManager.getTrueTypeFilter());236String[] t1s = fallbackDir.list(fontManager.getType1Filter());237int numTTFs = (ttfs == null) ? 0 : ttfs.length;238int numT1s = (t1s == null) ? 0 : t1s.length;239int len = numTTFs + numT1s;240if (numTTFs + numT1s == 0) {241return;242}243installedFallbackFontFiles = new String[len];244for (int i=0; i<numTTFs; i++) {245installedFallbackFontFiles[i] =246fallbackDir + File.separator + ttfs[i];247}248for (int i=0; i<numT1s; i++) {249installedFallbackFontFiles[i+numTTFs] =250fallbackDir + File.separator + t1s[i];251}252fontManager.registerFontsInDir(fallbackDirName);253}254}255256private File findImpl(String fname) {257File f = new File(fname + ".properties");258if (FontUtilities.debugFonts()) {259logger.info("Looking for text fontconfig file : " + f);260}261if (f.canRead()) {262if (FontUtilities.debugFonts()) {263logger.info("Found file : " + f);264}265isProperties = true;266return f;267}268f = new File(fname + ".bfc");269if (FontUtilities.debugFonts()) {270logger.info("Looking for binary fontconfig file : " + f);271}272if (f.canRead()) {273if (FontUtilities.debugFonts()) {274logger.info("Found file : " + f);275}276isProperties = false;277return f;278}279return null;280}281282private File findFontConfigFile(String dir) {283if (!(new File(dir)).exists()) {284return null;285}286String baseName = dir + File.separator + "fontconfig";287File configFile;288String osMajorVersion = null;289if (osVersion != null && osName != null) {290configFile = findImpl(baseName + "." + osName + "." + osVersion);291if (configFile != null) {292return configFile;293}294int decimalPointIndex = osVersion.indexOf('.');295if (decimalPointIndex != -1) {296osMajorVersion = osVersion.substring(0, osVersion.indexOf('.'));297configFile = findImpl(baseName + "." + osName + "." + osMajorVersion);298if (configFile != null) {299return configFile;300}301}302}303if (osName != null) {304configFile = findImpl(baseName + "." + osName);305if (configFile != null) {306return configFile;307}308}309if (osVersion != null) {310configFile = findImpl(baseName + "." + osVersion);311if (configFile != null) {312return configFile;313}314if (osMajorVersion != null) {315configFile = findImpl(baseName + "." + osMajorVersion);316if (configFile != null) {317return configFile;318}319}320}321foundOsSpecificFile = false;322323configFile = findImpl(baseName);324if (configFile != null) {325return configFile;326}327if (FontUtilities.debugFonts()) {328logger.info("Did not find a fontconfig file.");329}330return null;331}332333/* Initialize the internal data tables from binary format font334* configuration file.335*/336public static void loadBinary(InputStream inStream) throws IOException {337DataInputStream in = new DataInputStream(inStream);338head = readShortTable(in, HEAD_LENGTH);339int[] tableSizes = new int[INDEX_TABLEEND];340for (int i = 0; i < INDEX_TABLEEND; i++) {341tableSizes[i] = head[i + 1] - head[i];342}343table_scriptIDs = readShortTable(in, tableSizes[INDEX_scriptIDs]);344table_scriptFonts = readShortTable(in, tableSizes[INDEX_scriptFonts]);345table_elcIDs = readShortTable(in, tableSizes[INDEX_elcIDs]);346table_sequences = readShortTable(in, tableSizes[INDEX_sequences]);347table_fontfileNameIDs = readShortTable(in, tableSizes[INDEX_fontfileNameIDs]);348table_componentFontNameIDs = readShortTable(in, tableSizes[INDEX_componentFontNameIDs]);349table_filenames = readShortTable(in, tableSizes[INDEX_filenames]);350table_awtfontpaths = readShortTable(in, tableSizes[INDEX_awtfontpaths]);351table_exclusions = readShortTable(in, tableSizes[INDEX_exclusions]);352table_proportionals = readShortTable(in, tableSizes[INDEX_proportionals]);353table_scriptFontsMotif = readShortTable(in, tableSizes[INDEX_scriptFontsMotif]);354table_alphabeticSuffix = readShortTable(in, tableSizes[INDEX_alphabeticSuffix]);355table_stringIDs = readShortTable(in, tableSizes[INDEX_stringIDs]);356357//StringTable cache358stringCache = new String[table_stringIDs.length + 1];359360int len = tableSizes[INDEX_stringTable];361byte[] bb = new byte[len * 2];362table_stringTable = new char[len];363in.read(bb);364int i = 0, j = 0;365while (i < len) {366table_stringTable[i++] = (char)(bb[j++] << 8 | (bb[j++] & 0xff));367}368if (verbose) {369dump();370}371}372373/* Generate a binary format font configuration from internal data374* tables.375*/376public static void saveBinary(OutputStream out) throws IOException {377sanityCheck();378379DataOutputStream dataOut = new DataOutputStream(out);380writeShortTable(dataOut, head);381writeShortTable(dataOut, table_scriptIDs);382writeShortTable(dataOut, table_scriptFonts);383writeShortTable(dataOut, table_elcIDs);384writeShortTable(dataOut, table_sequences);385writeShortTable(dataOut, table_fontfileNameIDs);386writeShortTable(dataOut, table_componentFontNameIDs);387writeShortTable(dataOut, table_filenames);388writeShortTable(dataOut, table_awtfontpaths);389writeShortTable(dataOut, table_exclusions);390writeShortTable(dataOut, table_proportionals);391writeShortTable(dataOut, table_scriptFontsMotif);392writeShortTable(dataOut, table_alphabeticSuffix);393writeShortTable(dataOut, table_stringIDs);394//stringTable395dataOut.writeChars(new String(table_stringTable));396out.close();397if (verbose) {398dump();399}400}401402//private static boolean loadingProperties;403private static short stringIDNum;404private static short[] stringIDs;405private static StringBuilder stringTable;406407public static void loadProperties(InputStream in) throws IOException {408//loadingProperties = true;409//StringID starts from "1", "0" is reserved for "not defined"410stringIDNum = 1;411stringIDs = new short[1000];412stringTable = new StringBuilder(4096);413414if (verbose && logger == null) {415logger = PlatformLogger.getLogger("sun.awt.FontConfiguration");416}417new PropertiesHandler().load(in);418419//loadingProperties = false;420stringIDs = null;421stringTable = null;422}423424425/////////////////////////////////////////////////////////////////////426// methods for initializing the FontConfig //427/////////////////////////////////////////////////////////////////////428429/**430* set initLocale, initEncoding and initELC for this FontConfig object431* currently we just simply use the startup locale and encoding432*/433private void initFontConfig() {434initLocale = startupLocale;435initEncoding = encoding;436if (preferLocaleFonts && !willReorderForStartupLocale()) {437preferLocaleFonts = false;438}439initELC = getInitELC();440initAllComponentFonts();441}442443//"ELC" stands for "Encoding.Language.Country". This method returns444//the ID of the matched elc setting of "initLocale" in elcIDs table.445//If no match is found, it returns the default ID, which is446//"NULL.NULL.NULL" in elcIDs table.447private short getInitELC() {448if (initELC != -1) {449return initELC;450}451HashMap <String, Integer> elcIDs = new HashMap<String, Integer>();452for (int i = 0; i < table_elcIDs.length; i++) {453elcIDs.put(getString(table_elcIDs[i]), i);454}455String language = initLocale.getLanguage();456String country = initLocale.getCountry();457String elc;458if (elcIDs.containsKey(elc=initEncoding + "." + language + "." + country)459|| elcIDs.containsKey(elc=initEncoding + "." + language)460|| elcIDs.containsKey(elc=initEncoding)) {461initELC = elcIDs.get(elc).shortValue();462} else {463initELC = elcIDs.get("NULL.NULL.NULL").shortValue();464}465int i = 0;466while (i < table_alphabeticSuffix.length) {467if (initELC == table_alphabeticSuffix[i]) {468alphabeticSuffix = getString(table_alphabeticSuffix[i + 1]);469return initELC;470}471i += 2;472}473return initELC;474}475476public static boolean verbose;477private short initELC = -1;478private Locale initLocale;479private String initEncoding;480private String alphabeticSuffix;481482private short[][][] compFontNameIDs = new short[NUM_FONTS][NUM_STYLES][];483private int[][][] compExclusions = new int[NUM_FONTS][][];484private int[] compCoreNum = new int[NUM_FONTS];485486private Set<Short> coreFontNameIDs = new HashSet<Short>();487private Set<Short> fallbackFontNameIDs = new HashSet<Short>();488489private void initAllComponentFonts() {490short[] fallbackScripts = getFallbackScripts();491for (int fontIndex = 0; fontIndex < NUM_FONTS; fontIndex++) {492short[] coreScripts = getCoreScripts(fontIndex);493compCoreNum[fontIndex] = coreScripts.length;494/*495System.out.println("coreScriptID=" + table_sequences[initELC * 5 + fontIndex]);496for (int i = 0; i < coreScripts.length; i++) {497System.out.println(" " + i + " :" + getString(table_scriptIDs[coreScripts[i]]));498}499*/500//init exclusionRanges501int[][] exclusions = new int[coreScripts.length][];502for (int i = 0; i < coreScripts.length; i++) {503exclusions[i] = getExclusionRanges(coreScripts[i]);504}505compExclusions[fontIndex] = exclusions;506//init componentFontNames507for (int styleIndex = 0; styleIndex < NUM_STYLES; styleIndex++) {508int index;509short[] nameIDs = new short[coreScripts.length + fallbackScripts.length];510//core511for (index = 0; index < coreScripts.length; index++) {512nameIDs[index] = getComponentFontID(coreScripts[index],513fontIndex, styleIndex);514if (preferLocaleFonts && localeMap != null &&515fontManager.usingAlternateFontforJALocales()) {516nameIDs[index] = remapLocaleMap(fontIndex, styleIndex,517coreScripts[index], nameIDs[index]);518}519if (preferPropFonts) {520nameIDs[index] = remapProportional(fontIndex, nameIDs[index]);521}522//System.out.println("nameid=" + nameIDs[index]);523coreFontNameIDs.add(nameIDs[index]);524}525//fallback526for (int i = 0; i < fallbackScripts.length; i++) {527short id = getComponentFontID(fallbackScripts[i],528fontIndex, styleIndex);529if (preferLocaleFonts && localeMap != null &&530fontManager.usingAlternateFontforJALocales()) {531id = remapLocaleMap(fontIndex, styleIndex, fallbackScripts[i], id);532}533if (preferPropFonts) {534id = remapProportional(fontIndex, id);535}536if (contains(nameIDs, id, index)) {537continue;538}539/*540System.out.println("fontIndex=" + fontIndex + ", styleIndex=" + styleIndex541+ ", fbIndex=" + i + ",fbS=" + fallbackScripts[i] + ", id=" + id);542*/543fallbackFontNameIDs.add(id);544nameIDs[index++] = id;545}546if (index < nameIDs.length) {547short[] newNameIDs = new short[index];548System.arraycopy(nameIDs, 0, newNameIDs, 0, index);549nameIDs = newNameIDs;550}551compFontNameIDs[fontIndex][styleIndex] = nameIDs;552}553}554}555556private short remapLocaleMap(int fontIndex, int styleIndex, short scriptID, short fontID) {557String scriptName = getString(table_scriptIDs[scriptID]);558559String value = localeMap.get(scriptName);560if (value == null) {561String fontName = fontNames[fontIndex];562String styleName = styleNames[styleIndex];563value = localeMap.get(fontName + "." + styleName + "." + scriptName);564}565if (value == null) {566return fontID;567}568569for (int i = 0; i < table_componentFontNameIDs.length; i++) {570String name = getString(table_componentFontNameIDs[i]);571if (value.equalsIgnoreCase(name)) {572fontID = (short)i;573break;574}575}576return fontID;577}578579public static boolean hasMonoToPropMap() {580return table_proportionals != null && table_proportionals.length != 0;581}582583private short remapProportional(int fontIndex, short id) {584if (preferPropFonts &&585table_proportionals.length != 0 &&586fontIndex != 2 && //"monospaced"587fontIndex != 4) { //"dialoginput"588int i = 0;589while (i < table_proportionals.length) {590if (table_proportionals[i] == id) {591return table_proportionals[i + 1];592}593i += 2;594}595}596return id;597}598599/////////////////////////////////////////////////////////////////////600// Methods for handling font and style names //601/////////////////////////////////////////////////////////////////////602protected static final int NUM_FONTS = 5;603protected static final int NUM_STYLES = 4;604protected static final String[] fontNames605= {"serif", "sansserif", "monospaced", "dialog", "dialoginput"};606protected static final String[] publicFontNames607= {Font.SERIF, Font.SANS_SERIF, Font.MONOSPACED, Font.DIALOG,608Font.DIALOG_INPUT};609protected static final String[] styleNames610= {"plain", "bold", "italic", "bolditalic"};611612/**613* Checks whether the given font family name is a valid logical font name.614* The check is case insensitive.615*/616public static boolean isLogicalFontFamilyName(String fontName) {617return isLogicalFontFamilyNameLC(fontName.toLowerCase(Locale.ENGLISH));618}619620/**621* Checks whether the given font family name is a valid logical font name.622* The check is case sensitive.623*/624public static boolean isLogicalFontFamilyNameLC(String fontName) {625for (int i = 0; i < fontNames.length; i++) {626if (fontName.equals(fontNames[i])) {627return true;628}629}630return false;631}632633/**634* Checks whether the given style name is a valid logical font style name.635*/636private static boolean isLogicalFontStyleName(String styleName) {637for (int i = 0; i < styleNames.length; i++) {638if (styleName.equals(styleNames[i])) {639return true;640}641}642return false;643}644645/**646* Checks whether the given font face name is a valid logical font name.647* The check is case insensitive.648*/649public static boolean isLogicalFontFaceName(String fontName) {650return isLogicalFontFaceNameLC(fontName.toLowerCase(Locale.ENGLISH));651}652653/**654* Checks whether the given font face name is a valid logical font name.655* The check is case sensitive.656*/657public static boolean isLogicalFontFaceNameLC(String fontName) {658int period = fontName.indexOf('.');659if (period >= 0) {660String familyName = fontName.substring(0, period);661String styleName = fontName.substring(period + 1);662return isLogicalFontFamilyName(familyName) &&663isLogicalFontStyleName(styleName);664} else {665return isLogicalFontFamilyName(fontName);666}667}668669protected static int getFontIndex(String fontName) {670return getArrayIndex(fontNames, fontName);671}672673protected static int getStyleIndex(String styleName) {674return getArrayIndex(styleNames, styleName);675}676677private static int getArrayIndex(String[] names, String name) {678for (int i = 0; i < names.length; i++) {679if (name.equals(names[i])) {680return i;681}682}683assert false;684return 0;685}686687protected static int getStyleIndex(int style) {688switch (style) {689case Font.PLAIN:690return 0;691case Font.BOLD:692return 1;693case Font.ITALIC:694return 2;695case Font.BOLD | Font.ITALIC:696return 3;697default:698return 0;699}700}701702protected static String getFontName(int fontIndex) {703return fontNames[fontIndex];704}705706protected static String getStyleName(int styleIndex) {707return styleNames[styleIndex];708}709710/**711* Returns the font face name for the given logical font712* family name and style.713* The style argument is interpreted as in java.awt.Font.Font.714*/715public static String getLogicalFontFaceName(String familyName, int style) {716assert isLogicalFontFamilyName(familyName);717return familyName.toLowerCase(Locale.ENGLISH) + "." + getStyleString(style);718}719720/**721* Returns the string typically used in properties files722* for the given style.723* The style argument is interpreted as in java.awt.Font.Font.724*/725public static String getStyleString(int style) {726return getStyleName(getStyleIndex(style));727}728729/**730* Returns a fallback name for the given font name. For a few known731* font names, matching logical font names are returned. For all732* other font names, defaultFallback is returned.733* defaultFallback differs between AWT and 2D.734*/735public abstract String getFallbackFamilyName(String fontName, String defaultFallback);736737/**738* Returns the 1.1 equivalent for some old 1.0 font family names for739* which we need to maintain compatibility in some configurations.740* Returns null for other font names.741*/742protected String getCompatibilityFamilyName(String fontName) {743fontName = fontName.toLowerCase(Locale.ENGLISH);744if (fontName.equals("timesroman")) {745return "serif";746} else if (fontName.equals("helvetica")) {747return "sansserif";748} else if (fontName.equals("courier")) {749return "monospaced";750}751return null;752}753754protected static String[] installedFallbackFontFiles = null;755756/**757* Maps a file name given in the font configuration file758* to a format appropriate for the platform.759*/760protected String mapFileName(String fileName) {761return fileName;762}763764//////////////////////////////////////////////////////////////////////765// reordering //766//////////////////////////////////////////////////////////////////////767768/* Mappings from file encoding to font config name for font supporting769* the corresponding language. This is filled in by initReorderMap()770*/771protected HashMap<String, Object> reorderMap = null;772773/* Platform-specific mappings */774protected abstract void initReorderMap();775776/* Move item at index "src" to "dst", shuffling all values in777* between down778*/779private void shuffle(String[] seq, int src, int dst) {780if (dst >= src) {781return;782}783String tmp = seq[src];784for (int i=src; i>dst; i--) {785seq[i] = seq[i-1];786}787seq[dst] = tmp;788}789790/* Called to determine if there's a re-order sequence for this locale/791* encoding. If there's none then the caller can "bail" and avoid792* unnecessary work793*/794public static boolean willReorderForStartupLocale() {795return getReorderSequence() != null;796}797798private static Object getReorderSequence() {799if (fontConfig.reorderMap == null) {800fontConfig.initReorderMap();801}802HashMap<String, Object> reorderMap = fontConfig.reorderMap;803804/* Find the most specific mapping */805String language = startupLocale.getLanguage();806String country = startupLocale.getCountry();807Object val = reorderMap.get(encoding + "." + language + "." + country);808if (val == null) {809val = reorderMap.get(encoding + "." + language);810}811if (val == null) {812val = reorderMap.get(encoding);813}814return val;815}816817/* This method reorders the sequence such that the matches for the818* file encoding are moved ahead of other elements.819* If an encoding uses more than one font, they are all moved up.820*/821private void reorderSequenceForLocale(String[] seq) {822Object val = getReorderSequence();823if (val instanceof String) {824for (int i=0; i< seq.length; i++) {825if (seq[i].equals(val)) {826shuffle(seq, i, 0);827return;828}829}830} else if (val instanceof String[]) {831String[] fontLangs = (String[])val;832for (int l=0; l<fontLangs.length;l++) {833for (int i=0; i<seq.length;i++) {834if (seq[i].equals(fontLangs[l])) {835shuffle(seq, i, l);836}837}838}839}840}841842private static Vector<String> splitSequence(String sequence) {843//String.split would be more convenient, but incurs big performance penalty844Vector<String> parts = new Vector<>();845int start = 0;846int end;847while ((end = sequence.indexOf(',', start)) >= 0) {848parts.add(sequence.substring(start, end));849start = end + 1;850}851if (sequence.length() > start) {852parts.add(sequence.substring(start, sequence.length()));853}854return parts;855}856857protected String[] split(String sequence) {858Vector<String> v = splitSequence(sequence);859return v.toArray(new String[0]);860}861862////////////////////////////////////////////////////////////////////////863// Methods for extracting information from the fontconfig data for AWT//864////////////////////////////////////////////////////////////////////////865private Hashtable<String, Charset> charsetRegistry = new Hashtable<>(5);866867/**868* Returns FontDescriptors describing the physical fonts used for the869* given logical font name and style. The font name is interpreted870* in a case insensitive way.871* The style argument is interpreted as in java.awt.Font.Font.872*/873public FontDescriptor[] getFontDescriptors(String fontName, int style) {874assert isLogicalFontFamilyName(fontName);875fontName = fontName.toLowerCase(Locale.ENGLISH);876int fontIndex = getFontIndex(fontName);877int styleIndex = getStyleIndex(style);878return getFontDescriptors(fontIndex, styleIndex);879}880private FontDescriptor[][][] fontDescriptors =881new FontDescriptor[NUM_FONTS][NUM_STYLES][];882883private FontDescriptor[] getFontDescriptors(int fontIndex, int styleIndex) {884FontDescriptor[] descriptors = fontDescriptors[fontIndex][styleIndex];885if (descriptors == null) {886descriptors = buildFontDescriptors(fontIndex, styleIndex);887fontDescriptors[fontIndex][styleIndex] = descriptors;888}889return descriptors;890}891892protected FontDescriptor[] buildFontDescriptors(int fontIndex, int styleIndex) {893String fontName = fontNames[fontIndex];894String styleName = styleNames[styleIndex];895896short[] scriptIDs = getCoreScripts(fontIndex);897short[] nameIDs = compFontNameIDs[fontIndex][styleIndex];898String[] sequence = new String[scriptIDs.length];899String[] names = new String[scriptIDs.length];900for (int i = 0; i < sequence.length; i++) {901names[i] = getComponentFontName(nameIDs[i]);902sequence[i] = getScriptName(scriptIDs[i]);903if (alphabeticSuffix != null && "alphabetic".equals(sequence[i])) {904sequence[i] = sequence[i] + "/" + alphabeticSuffix;905}906}907int[][] fontExclusionRanges = compExclusions[fontIndex];908909FontDescriptor[] descriptors = new FontDescriptor[names.length];910911for (int i = 0; i < names.length; i++) {912String awtFontName;913String encoding;914915awtFontName = makeAWTFontName(names[i], sequence[i]);916917// look up character encoding918encoding = getEncoding(names[i], sequence[i]);919if (encoding == null) {920encoding = "default";921}922CharsetEncoder enc923= getFontCharsetEncoder(encoding.trim(), awtFontName);924925// we already have the exclusion ranges926int[] exclusionRanges = fontExclusionRanges[i];927928// create descriptor929descriptors[i] = new FontDescriptor(awtFontName, enc, exclusionRanges);930}931return descriptors;932}933934/**935* Returns the AWT font name for the given platform font name and936* character subset.937*/938protected String makeAWTFontName(String platformFontName,939String characterSubsetName) {940return platformFontName;941}942943/**944* Returns the java.io name of the platform character encoding for the945* given AWT font name and character subset. May return "default"946* to indicate that getDefaultFontCharset should be called to obtain947* a charset encoder.948*/949protected abstract String getEncoding(String awtFontName,950String characterSubsetName);951952private CharsetEncoder getFontCharsetEncoder(final String charsetName,953String fontName) {954955Charset fc = null;956if (charsetName.equals("default")) {957fc = charsetRegistry.get(fontName);958} else {959fc = charsetRegistry.get(charsetName);960}961if (fc != null) {962return fc.newEncoder();963}964965if (!charsetName.startsWith("sun.awt.") && !charsetName.equals("default")) {966fc = Charset.forName(charsetName);967} else {968@SuppressWarnings("removal")969Class<?> fcc = AccessController.doPrivileged(new PrivilegedAction<Class<?>>() {970public Class<?> run() {971try {972return Class.forName(charsetName, true,973ClassLoader.getSystemClassLoader());974} catch (ClassNotFoundException e) {975}976return null;977}978});979980if (fcc != null) {981try {982fc = (Charset) fcc.getDeclaredConstructor().newInstance();983} catch (Exception e) {984}985}986}987if (fc == null) {988fc = getDefaultFontCharset(fontName);989}990991if (charsetName.equals("default")){992charsetRegistry.put(fontName, fc);993} else {994charsetRegistry.put(charsetName, fc);995}996return fc.newEncoder();997}998999protected abstract Charset getDefaultFontCharset(1000String fontName);10011002/* This retrieves the platform font directories (path) calculated1003* by setAWTFontPathSequence(String[]). The default implementation1004* returns null, its expected that X11 platforms may return1005* non-null.1006*/1007public HashSet<String> getAWTFontPathSet() {1008return null;1009}10101011////////////////////////////////////////////////////////////////////////1012// methods for extracting information from the fontconfig data for 2D //1013////////////////////////////////////////////////////////////////////////10141015/**1016* Returns an array of composite font descriptors for all logical font1017* faces.1018*/1019public CompositeFontDescriptor[] get2DCompositeFontInfo() {1020CompositeFontDescriptor[] result =1021new CompositeFontDescriptor[NUM_FONTS * NUM_STYLES];1022String defaultFontFile = fontManager.getDefaultFontFile();1023String defaultFontFaceName = fontManager.getDefaultFontFaceName();10241025for (int fontIndex = 0; fontIndex < NUM_FONTS; fontIndex++) {1026String fontName = publicFontNames[fontIndex];10271028// determine exclusion ranges for font1029// AWT uses separate exclusion range array per component font.1030// 2D packs all range boundaries into one array.1031// Both use separate entries for lower and upper boundary.1032int[][] exclusions = compExclusions[fontIndex];1033int numExclusionRanges = 0;1034for (int i = 0; i < exclusions.length; i++) {1035numExclusionRanges += exclusions[i].length;1036}1037int[] exclusionRanges = new int[numExclusionRanges];1038int[] exclusionRangeLimits = new int[exclusions.length];1039int exclusionRangeIndex = 0;1040int exclusionRangeLimitIndex = 0;1041for (int i = 0; i < exclusions.length; i++) {1042int[] componentRanges = exclusions[i];1043for (int j = 0; j < componentRanges.length; ) {1044int value = componentRanges[j];1045exclusionRanges[exclusionRangeIndex++] = componentRanges[j++];1046exclusionRanges[exclusionRangeIndex++] = componentRanges[j++];1047}1048exclusionRangeLimits[i] = exclusionRangeIndex;1049}1050// other info is per style1051for (int styleIndex = 0; styleIndex < NUM_STYLES; styleIndex++) {1052int maxComponentFontCount = compFontNameIDs[fontIndex][styleIndex].length;1053// fall back fonts listed in the lib/fonts/fallback directory1054if (installedFallbackFontFiles != null) {1055maxComponentFontCount += installedFallbackFontFiles.length;1056}1057String faceName = fontName + "." + styleNames[styleIndex];10581059// determine face names and file names of component fonts1060String[] componentFaceNames = new String[maxComponentFontCount];1061String[] componentFileNames = new String[maxComponentFontCount];10621063int index;1064for (index = 0; index < compFontNameIDs[fontIndex][styleIndex].length; index++) {1065short fontNameID = compFontNameIDs[fontIndex][styleIndex][index];1066short fileNameID = getComponentFileID(fontNameID);1067componentFaceNames[index] = getFaceNameFromComponentFontName(getComponentFontName(fontNameID));1068componentFileNames[index] = mapFileName(getComponentFileName(fileNameID));1069if (componentFileNames[index] == null ||1070needToSearchForFile(componentFileNames[index])) {1071componentFileNames[index] = getFileNameFromComponentFontName(getComponentFontName(fontNameID));1072}1073/*1074System.out.println(publicFontNames[fontIndex] + "." + styleNames[styleIndex] + "."1075+ getString(table_scriptIDs[coreScripts[index]]) + "=" + componentFileNames[index]);1076*/1077}10781079if (installedFallbackFontFiles != null) {1080for (int ifb=0; ifb<installedFallbackFontFiles.length; ifb++) {1081componentFaceNames[index] = null;1082componentFileNames[index] = installedFallbackFontFiles[ifb];1083index++;1084}1085}10861087if (index < maxComponentFontCount) {1088String[] newComponentFaceNames = new String[index];1089System.arraycopy(componentFaceNames, 0, newComponentFaceNames, 0, index);1090componentFaceNames = newComponentFaceNames;1091String[] newComponentFileNames = new String[index];1092System.arraycopy(componentFileNames, 0, newComponentFileNames, 0, index);1093componentFileNames = newComponentFileNames;1094}1095// exclusion range limit array length must match component face name1096// array length - native code relies on this10971098int[] clippedExclusionRangeLimits = exclusionRangeLimits;1099if (index != clippedExclusionRangeLimits.length) {1100int len = exclusionRangeLimits.length;1101clippedExclusionRangeLimits = new int[index];1102System.arraycopy(exclusionRangeLimits, 0, clippedExclusionRangeLimits, 0, len);1103//padding for various fallback fonts1104for (int i = len; i < index; i++) {1105clippedExclusionRangeLimits[i] = exclusionRanges.length;1106}1107}1108/*1109System.out.println(faceName + ":");1110for (int i = 0; i < componentFileNames.length; i++) {1111System.out.println(" " + componentFaceNames[i]1112+ " -> " + componentFileNames[i]);1113}1114*/1115result[fontIndex * NUM_STYLES + styleIndex]1116= new CompositeFontDescriptor(1117faceName,1118compCoreNum[fontIndex],1119componentFaceNames,1120componentFileNames,1121exclusionRanges,1122clippedExclusionRangeLimits);1123}1124}1125return result;1126}11271128protected abstract String getFaceNameFromComponentFontName(String componentFontName);1129protected abstract String getFileNameFromComponentFontName(String componentFontName);11301131/*1132public class 2dFont {1133public String platformName;1134public String fontfileName;1135}1136private 2dFont [] componentFonts = null;1137*/11381139/* Used on Linux to test if a file referenced in a font configuration1140* file exists in the location that is expected. If it does, no need1141* to search for it. If it doesn't then unless its a fallback font,1142* return that expensive code should be invoked to search for the font.1143*/1144HashMap<String, Boolean> existsMap;1145public boolean needToSearchForFile(String fileName) {1146if (!FontUtilities.isLinux) {1147return false;1148} else if (existsMap == null) {1149existsMap = new HashMap<String, Boolean>();1150}1151Boolean exists = existsMap.get(fileName);1152if (exists == null) {1153/* call getNumberCoreFonts() to ensure these are initialised, and1154* if this file isn't for a core component, ie, is a for a fallback1155* font which very typically isn't available, then can't afford1156* to take the start-up penalty to search for it.1157*/1158getNumberCoreFonts();1159if (!coreFontFileNames.contains(fileName)) {1160exists = Boolean.TRUE;1161} else {1162exists = Boolean.valueOf((new File(fileName)).exists());1163existsMap.put(fileName, exists);1164if (FontUtilities.debugFonts() &&1165exists == Boolean.FALSE) {1166logger.warning("Couldn't locate font file " + fileName);1167}1168}1169}1170return exists == Boolean.FALSE;1171}11721173private int numCoreFonts = -1;1174private String[] componentFonts = null;1175HashMap <String, String> filenamesMap = new HashMap<String, String>();1176HashSet <String> coreFontFileNames = new HashSet<String>();11771178/* Return the number of core fonts. Note this isn't thread safe but1179* a calling thread can call this and getPlatformFontNames() in either1180* order.1181*/1182public int getNumberCoreFonts() {1183if (numCoreFonts == -1) {1184numCoreFonts = coreFontNameIDs.size();1185Short[] emptyShortArray = new Short[0];1186Short[] core = coreFontNameIDs.toArray(emptyShortArray);1187Short[] fallback = fallbackFontNameIDs.toArray(emptyShortArray);11881189int numFallbackFonts = 0;1190int i;1191for (i = 0; i < fallback.length; i++) {1192if (coreFontNameIDs.contains(fallback[i])) {1193fallback[i] = null;1194continue;1195}1196numFallbackFonts++;1197}1198componentFonts = new String[numCoreFonts + numFallbackFonts];1199String filename = null;1200for (i = 0; i < core.length; i++) {1201short fontid = core[i];1202short fileid = getComponentFileID(fontid);1203componentFonts[i] = getComponentFontName(fontid);1204String compFileName = getComponentFileName(fileid);1205if (compFileName != null) {1206coreFontFileNames.add(compFileName);1207}1208filenamesMap.put(componentFonts[i], mapFileName(compFileName));1209}1210for (int j = 0; j < fallback.length; j++) {1211if (fallback[j] != null) {1212short fontid = fallback[j];1213short fileid = getComponentFileID(fontid);1214componentFonts[i] = getComponentFontName(fontid);1215filenamesMap.put(componentFonts[i],1216mapFileName(getComponentFileName(fileid)));1217i++;1218}1219}1220}1221return numCoreFonts;1222}12231224/* Return all platform font names used by this font configuration.1225* The first getNumberCoreFonts() entries are guaranteed to be the1226* core fonts - ie no fall back only fonts.1227*/1228public String[] getPlatformFontNames() {1229if (numCoreFonts == -1) {1230getNumberCoreFonts();1231}1232return componentFonts;1233}12341235/**1236* Returns a file name for the physical font represented by this platform font name,1237* if the font configuration has such information available, or null if the1238* information is unavailable. The file name returned is just a hint; a null return1239* value doesn't necessarily mean that the font is unavailable, nor does a non-null1240* return value guarantee that the file exists and contains the physical font.1241* The file name can be an absolute or a relative path name.1242*/1243public String getFileNameFromPlatformName(String platformName) {1244// get2DCompositeFontInfo1245// -> getFileNameFromComponentfontName() (W/M)1246// -> getFileNameFromPlatformName()1247// it's a waste of time on Win32, but I have to give X11 a chance to1248// call getFileNameFromXLFD()1249return filenamesMap.get(platformName);1250}12511252/**1253* Returns a configuration specific path to be appended to the font1254* search path.1255*/1256public String getExtraFontPath() {1257return getString(head[INDEX_appendedfontpath]);1258}12591260public String getVersion() {1261return getString(head[INDEX_version]);1262}12631264/* subclass support */1265protected static FontConfiguration getFontConfiguration() {1266return fontConfig;1267}12681269protected void setFontConfiguration() {1270fontConfig = this; /* static initialization */1271}12721273//////////////////////////////////////////////////////////////////////1274// FontConfig data tables and the index constants in binary file //1275//////////////////////////////////////////////////////////////////////1276/* The binary font configuration file begins with a short[] "head", which1277* contains the offsets to the starts of the individual data table which1278* immediately follow. The current implementation includes the tables shown1279* below.1280*1281* (00) table_scriptIDs :stringIDs of all defined CharacterSubsetNames1282* (01) table_scriptFonts :scriptID x fontIndex x styleIndex->1283* PlatformFontNameID mapping. Each scriptID might1284* have 1 or 20 entries depends on if it is defined1285* via a "allfonts.CharacterSubsetname" or a list of1286* "LogicalFontName.StyleName.CharacterSubsetName"1287* entries, positive entry means it's a "allfonts"1288* entry, a negative value means this is a offset to1289* a NUM_FONTS x NUM_STYLES subtable.1290* (02) table_elcIDs :stringIDs of all defined ELC names, string1291* "NULL.NULL.NULL" is used for "default"1292* (03) table_sequences :elcID x logicalFont -> scriptIDs table defined1293* by "sequence.allfonts/LogicalFontName.ELC" in1294* font configuration file, each "elcID" has1295* NUM_FONTS (5) entries in this table.1296* (04) table_fontfileNameIDs1297* :stringIDs of all defined font file names1298* (05) table_componentFontNameIDs1299* :stringIDs of all defined PlatformFontNames1300* (06) table_filenames :platformFontNamesID->fontfileNameID mapping1301* table, the index is the platformFontNamesID.1302* (07) table_awtfontpaths :CharacterSubsetNames->awtfontpaths mapping table,1303* the index is the CharacterSubsetName's stringID1304* and content is the stringID of awtfontpath.1305* (08) table_exclusions :scriptID -> exclusionRanges mapping table,1306* the index is the scriptID and the content is1307a id of an exclusionRanges int[].1308* (09) table_proportionals:list of pairs of PlatformFontNameIDs, stores1309* the replacement info defined by "proportional"1310* keyword.1311* (10) table_scriptFontsMotif1312* :same as (01) except this table stores the1313* info defined with ".motif" keyword1314* (11) table_alphabeticSuffix1315* :elcID -> stringID of alphabetic/XXXX entries1316* (12) table_stringIDs :The index of this table is the string ID, the1317* content is the "start index" of this string in1318* stringTable, use the start index of next entry1319* as the "end index".1320* (13) table_stringTable :The real storage of all character strings defined1321* /used this font configuration, need a pair of1322* "start" and "end" indices to access.1323* (14) reserved1324* (15) table_fallbackScripts1325* :stringIDs of fallback CharacterSubsetnames, stored1326* in the order of they are defined in sequence.fallback.1327* (16) table_appendedfontpath1328* :stringtID of the "appendedfontpath" defined.1329* (17) table_version :stringID of the version number of this fontconfig file.1330*/1331private static final int HEAD_LENGTH = 20;1332private static final int INDEX_scriptIDs = 0;1333private static final int INDEX_scriptFonts = 1;1334private static final int INDEX_elcIDs = 2;1335private static final int INDEX_sequences = 3;1336private static final int INDEX_fontfileNameIDs = 4;1337private static final int INDEX_componentFontNameIDs = 5;1338private static final int INDEX_filenames = 6;1339private static final int INDEX_awtfontpaths = 7;1340private static final int INDEX_exclusions = 8;1341private static final int INDEX_proportionals = 9;1342private static final int INDEX_scriptFontsMotif = 10;1343private static final int INDEX_alphabeticSuffix = 11;1344private static final int INDEX_stringIDs = 12;1345private static final int INDEX_stringTable = 13;1346private static final int INDEX_TABLEEND = 14;1347private static final int INDEX_fallbackScripts = 15;1348private static final int INDEX_appendedfontpath = 16;1349private static final int INDEX_version = 17;13501351private static short[] head;1352private static short[] table_scriptIDs;1353private static short[] table_scriptFonts;1354private static short[] table_elcIDs;1355private static short[] table_sequences;1356private static short[] table_fontfileNameIDs;1357private static short[] table_componentFontNameIDs;1358private static short[] table_filenames;1359protected static short[] table_awtfontpaths;1360private static short[] table_exclusions;1361private static short[] table_proportionals;1362private static short[] table_scriptFontsMotif;1363private static short[] table_alphabeticSuffix;1364private static short[] table_stringIDs;1365private static char[] table_stringTable;13661367/**1368* Checks consistencies of complied fontconfig data. This method1369* is called only at the build-time from1370* build.tools.compilefontconfig.CompileFontConfig.1371*/1372private static void sanityCheck() {1373int errors = 0;13741375//This method will only be called during build time, do we1376//need do PrivilegedAction?1377@SuppressWarnings("removal")1378String osName = java.security.AccessController.doPrivileged(1379new java.security.PrivilegedAction<String>() {1380public String run() {1381return System.getProperty("os.name");1382}1383});13841385//componentFontNameID starts from "1"1386for (int ii = 1; ii < table_filenames.length; ii++) {1387if (table_filenames[ii] == -1) {1388// The corresponding finename entry for a component1389// font name is mandatory on Windows, but it's1390// optional on Solaris and Linux.1391if (osName.contains("Windows")) {1392System.err.println("\n Error: <filename."1393+ getString(table_componentFontNameIDs[ii])1394+ "> entry is missing!!!");1395errors++;1396} else {1397if (verbose && !isEmpty(table_filenames)) {1398System.err.println("\n Note: 'filename' entry is undefined for \""1399+ getString(table_componentFontNameIDs[ii])1400+ "\"");1401}1402}1403}1404}1405for (int ii = 0; ii < table_scriptIDs.length; ii++) {1406short fid = table_scriptFonts[ii];1407if (fid == 0) {1408System.out.println("\n Error: <allfonts."1409+ getString(table_scriptIDs[ii])1410+ "> entry is missing!!!");1411errors++;1412continue;1413} else if (fid < 0) {1414fid = (short)-fid;1415for (int iii = 0; iii < NUM_FONTS; iii++) {1416for (int iij = 0; iij < NUM_STYLES; iij++) {1417int jj = iii * NUM_STYLES + iij;1418short ffid = table_scriptFonts[fid + jj];1419if (ffid == 0) {1420System.err.println("\n Error: <"1421+ getFontName(iii) + "."1422+ getStyleName(iij) + "."1423+ getString(table_scriptIDs[ii])1424+ "> entry is missing!!!");1425errors++;1426}1427}1428}1429}1430}1431if (errors != 0) {1432System.err.println("!!THERE ARE " + errors + " ERROR(S) IN "1433+ "THE FONTCONFIG FILE, PLEASE CHECK ITS CONTENT!!\n");1434System.exit(1);1435}1436}14371438private static boolean isEmpty(short[] a) {1439for (short s : a) {1440if (s != -1) {1441return false;1442}1443}1444return true;1445}14461447//dump the fontconfig data tables1448private static void dump() {1449System.out.println("\n----Head Table------------");1450for (int ii = 0; ii < HEAD_LENGTH; ii++) {1451System.out.println(" " + ii + " : " + head[ii]);1452}1453System.out.println("\n----scriptIDs-------------");1454printTable(table_scriptIDs, 0);1455System.out.println("\n----scriptFonts----------------");1456for (int ii = 0; ii < table_scriptIDs.length; ii++) {1457short fid = table_scriptFonts[ii];1458if (fid >= 0) {1459System.out.println(" allfonts."1460+ getString(table_scriptIDs[ii])1461+ "="1462+ getString(table_componentFontNameIDs[fid]));1463}1464}1465for (int ii = 0; ii < table_scriptIDs.length; ii++) {1466short fid = table_scriptFonts[ii];1467if (fid < 0) {1468fid = (short)-fid;1469for (int iii = 0; iii < NUM_FONTS; iii++) {1470for (int iij = 0; iij < NUM_STYLES; iij++) {1471int jj = iii * NUM_STYLES + iij;1472short ffid = table_scriptFonts[fid + jj];1473System.out.println(" "1474+ getFontName(iii) + "."1475+ getStyleName(iij) + "."1476+ getString(table_scriptIDs[ii])1477+ "="1478+ getString(table_componentFontNameIDs[ffid]));1479}1480}14811482}1483}1484System.out.println("\n----elcIDs----------------");1485printTable(table_elcIDs, 0);1486System.out.println("\n----sequences-------------");1487for (int ii = 0; ii< table_elcIDs.length; ii++) {1488System.out.println(" " + ii + "/" + getString(table_elcIDs[ii]));1489short[] ss = getShortArray(table_sequences[ii * NUM_FONTS + 0]);1490for (int jj = 0; jj < ss.length; jj++) {1491System.out.println(" " + getString(table_scriptIDs[ss[jj]]));1492}1493}1494System.out.println("\n----fontfileNameIDs-------");1495printTable(table_fontfileNameIDs, 0);14961497System.out.println("\n----componentFontNameIDs--");1498printTable(table_componentFontNameIDs, 1);1499System.out.println("\n----filenames-------------");1500for (int ii = 0; ii < table_filenames.length; ii++) {1501if (table_filenames[ii] == -1) {1502System.out.println(" " + ii + " : null");1503} else {1504System.out.println(" " + ii + " : "1505+ getString(table_fontfileNameIDs[table_filenames[ii]]));1506}1507}1508System.out.println("\n----awtfontpaths---------");1509for (int ii = 0; ii < table_awtfontpaths.length; ii++) {1510System.out.println(" " + getString(table_scriptIDs[ii])1511+ " : "1512+ getString(table_awtfontpaths[ii]));1513}1514System.out.println("\n----proportionals--------");1515for (int ii = 0; ii < table_proportionals.length; ii++) {1516System.out.println(" "1517+ getString(table_componentFontNameIDs[table_proportionals[ii++]])1518+ " -> "1519+ getString(table_componentFontNameIDs[table_proportionals[ii]]));1520}1521int i = 0;1522System.out.println("\n----alphabeticSuffix----");1523while (i < table_alphabeticSuffix.length) {1524System.out.println(" " + getString(table_elcIDs[table_alphabeticSuffix[i++]])1525+ " -> " + getString(table_alphabeticSuffix[i++]));1526}1527System.out.println("\n----String Table---------");1528System.out.println(" stringID: Num =" + table_stringIDs.length);1529System.out.println(" stringTable: Size=" + table_stringTable.length * 2);15301531System.out.println("\n----fallbackScriptIDs---");1532short[] fbsIDs = getShortArray(head[INDEX_fallbackScripts]);1533for (int ii = 0; ii < fbsIDs.length; ii++) {1534System.out.println(" " + getString(table_scriptIDs[fbsIDs[ii]]));1535}1536System.out.println("\n----appendedfontpath-----");1537System.out.println(" " + getString(head[INDEX_appendedfontpath]));1538System.out.println("\n----Version--------------");1539System.out.println(" " + getString(head[INDEX_version]));1540}154115421543//////////////////////////////////////////////////////////////////////1544// Data table access methods //1545//////////////////////////////////////////////////////////////////////15461547/* Return the fontID of the platformFontName defined in this font config1548* by "LogicalFontName.StyleName.CharacterSubsetName" entry or1549* "allfonts.CharacterSubsetName" entry in properties format fc file.1550*/1551protected static short getComponentFontID(short scriptID, int fontIndex, int styleIndex) {1552short fid = table_scriptFonts[scriptID];1553//System.out.println("fid=" + fid + "/ scriptID=" + scriptID + ", fi=" + fontIndex + ", si=" + styleIndex);1554if (fid >= 0) {1555//"allfonts"1556return fid;1557} else {1558return table_scriptFonts[-fid + fontIndex * NUM_STYLES + styleIndex];1559}1560}15611562/* Same as getCompoentFontID() except this method returns the fontID define by1563* "xxxx.motif" entry.1564*/1565protected static short getComponentFontIDMotif(short scriptID, int fontIndex, int styleIndex) {1566if (table_scriptFontsMotif.length == 0) {1567return 0;1568}1569short fid = table_scriptFontsMotif[scriptID];1570if (fid >= 0) {1571//"allfonts" > 0 or "not defined" == 01572return fid;1573} else {1574return table_scriptFontsMotif[-fid + fontIndex * NUM_STYLES + styleIndex];1575}1576}15771578private static int[] getExclusionRanges(short scriptID) {1579short exID = table_exclusions[scriptID];1580if (exID == 0) {1581return EMPTY_INT_ARRAY;1582} else {1583char[] exChar = getString(exID).toCharArray();1584int[] exInt = new int[exChar.length / 2];1585int i = 0;1586for (int j = 0; j < exInt.length; j++) {1587exInt[j] = (exChar[i++] << 16) + (exChar[i++] & 0xffff);1588}1589return exInt;1590}1591}15921593private static boolean contains(short[] IDs, short id, int limit) {1594for (int i = 0; i < limit; i++) {1595if (IDs[i] == id) {1596return true;1597}1598}1599return false;1600}16011602/* Return the PlatformFontName from its fontID*/1603protected static String getComponentFontName(short id) {1604if (id < 0) {1605return null;1606}1607return getString(table_componentFontNameIDs[id]);1608}16091610private static String getComponentFileName(short id) {1611if (id < 0) {1612return null;1613}1614return getString(table_fontfileNameIDs[id]);1615}16161617//componentFontID -> componentFileID1618private static short getComponentFileID(short nameID) {1619return table_filenames[nameID];1620}16211622private static String getScriptName(short scriptID) {1623return getString(table_scriptIDs[scriptID]);1624}16251626private HashMap<String, Short> reorderScripts;1627protected short[] getCoreScripts(int fontIndex) {1628short elc = getInitELC();1629/*1630System.out.println("getCoreScripts: elc=" + elc + ", fontIndex=" + fontIndex);1631short[] ss = getShortArray(table_sequences[elc * NUM_FONTS + fontIndex]);1632for (int i = 0; i < ss.length; i++) {1633System.out.println(" " + getString((short)table_scriptIDs[ss[i]]));1634}1635*/1636short[] scripts = getShortArray(table_sequences[elc * NUM_FONTS + fontIndex]);1637if (preferLocaleFonts) {1638if (reorderScripts == null) {1639reorderScripts = new HashMap<String, Short>();1640}1641String[] ss = new String[scripts.length];1642for (int i = 0; i < ss.length; i++) {1643ss[i] = getScriptName(scripts[i]);1644reorderScripts.put(ss[i], scripts[i]);1645}1646reorderSequenceForLocale(ss);1647for (int i = 0; i < ss.length; i++) {1648scripts[i] = reorderScripts.get(ss[i]);1649}1650}1651return scripts;1652}16531654private static short[] getFallbackScripts() {1655return getShortArray(head[INDEX_fallbackScripts]);1656}16571658private static void printTable(short[] list, int start) {1659for (int i = start; i < list.length; i++) {1660System.out.println(" " + i + " : " + getString(list[i]));1661}1662}16631664private static short[] readShortTable(DataInputStream in, int len )1665throws IOException {1666if (len == 0) {1667return EMPTY_SHORT_ARRAY;1668}1669short[] data = new short[len];1670byte[] bb = new byte[len * 2];1671in.read(bb);1672int i = 0,j = 0;1673while (i < len) {1674data[i++] = (short)(bb[j++] << 8 | (bb[j++] & 0xff));1675}1676return data;1677}16781679private static void writeShortTable(DataOutputStream out, short[] data)1680throws IOException {1681for (short val : data) {1682out.writeShort(val);1683}1684}16851686private static short[] toList(HashMap<String, Short> map) {1687short[] list = new short[map.size()];1688Arrays.fill(list, (short) -1);1689for (Entry<String, Short> entry : map.entrySet()) {1690list[entry.getValue()] = getStringID(entry.getKey());1691}1692return list;1693}16941695//runtime cache1696private static String[] stringCache;1697protected static String getString(short stringID) {1698if (stringID == 0)1699return null;1700/*1701if (loadingProperties) {1702return stringTable.substring(stringIDs[stringID],1703stringIDs[stringID+1]);1704}1705*/1706//sync if we want it to be MT-enabled1707if (stringCache[stringID] == null){1708stringCache[stringID] =1709new String (table_stringTable,1710table_stringIDs[stringID],1711table_stringIDs[stringID+1] - table_stringIDs[stringID]);1712}1713return stringCache[stringID];1714}17151716private static short[] getShortArray(short shortArrayID) {1717String s = getString(shortArrayID);1718char[] cc = s.toCharArray();1719short[] ss = new short[cc.length];1720for (int i = 0; i < cc.length; i++) {1721ss[i] = (short)(cc[i] & 0xffff);1722}1723return ss;1724}17251726private static short getStringID(String s) {1727if (s == null) {1728return (short)0;1729}1730short pos0 = (short)stringTable.length();1731stringTable.append(s);1732short pos1 = (short)stringTable.length();17331734stringIDs[stringIDNum] = pos0;1735stringIDs[stringIDNum + 1] = pos1;1736stringIDNum++;1737if (stringIDNum + 1 >= stringIDs.length) {1738short[] tmp = new short[stringIDNum + 1000];1739System.arraycopy(stringIDs, 0, tmp, 0, stringIDNum);1740stringIDs = tmp;1741}1742return (short)(stringIDNum - 1);1743}17441745private static short getShortArrayID(short[] sa) {1746char[] cc = new char[sa.length];1747for (int i = 0; i < sa.length; i ++) {1748cc[i] = (char)sa[i];1749}1750String s = new String(cc);1751return getStringID(s);1752}17531754//utility "empty" objects1755private static final int[] EMPTY_INT_ARRAY = new int[0];1756private static final String[] EMPTY_STRING_ARRAY = new String[0];1757private static final short[] EMPTY_SHORT_ARRAY = new short[0];1758private static final String UNDEFINED_COMPONENT_FONT = "unknown";17591760//////////////////////////////////////////////////////////////////////////1761//Convert the FontConfig data in Properties file to binary data tables //1762//////////////////////////////////////////////////////////////////////////1763static class PropertiesHandler {1764public void load(InputStream in) throws IOException {1765initLogicalNameStyle();1766initHashMaps();1767FontProperties fp = new FontProperties();1768fp.load(in);1769initBinaryTable();1770}17711772private void initBinaryTable() {1773//(0)1774head = new short[HEAD_LENGTH];1775head[INDEX_scriptIDs] = (short)HEAD_LENGTH;17761777table_scriptIDs = toList(scriptIDs);1778//(1)a: scriptAllfonts scriptID/allfonts -> componentFontNameID1779// b: scriptFonts scriptID -> componentFontNameID[20]1780//if we have a "allfonts.script" def, then we just put1781//the "-platformFontID" value in the slot, otherwise the slot1782//value is "offset" which "offset" is where 20 entries located1783//in the table attached.1784head[INDEX_scriptFonts] = (short)(head[INDEX_scriptIDs] + table_scriptIDs.length);1785int len = table_scriptIDs.length + scriptFonts.size() * 20;1786table_scriptFonts = new short[len];17871788for (Entry<Short, Short> entry : scriptAllfonts.entrySet()) {1789table_scriptFonts[entry.getKey().intValue()] = entry.getValue();1790}1791int off = table_scriptIDs.length;1792for (Entry<Short, Short[]> entry : scriptFonts.entrySet()) {1793table_scriptFonts[entry.getKey().intValue()] = (short)-off;1794Short[] v = entry.getValue();1795for (int i = 0; i < 20; i++) {1796if (v[i] != null) {1797table_scriptFonts[off++] = v[i];1798} else {1799table_scriptFonts[off++] = 0;1800}1801}1802}18031804//(2)1805head[INDEX_elcIDs] = (short)(head[INDEX_scriptFonts] + table_scriptFonts.length);1806table_elcIDs = toList(elcIDs);18071808//(3) sequences elcID -> XXXX[1|5] -> scriptID[]1809head[INDEX_sequences] = (short)(head[INDEX_elcIDs] + table_elcIDs.length);1810table_sequences = new short[elcIDs.size() * NUM_FONTS];1811for (Entry<Short, short[]> entry : sequences.entrySet()) {1812//table_sequences[entry.getKey().intValue()] = (short)-off;1813int k = entry.getKey().intValue();1814short[] v = entry.getValue();1815/*1816System.out.println("elc=" + k + "/" + getString((short)table_elcIDs[k]));1817short[] ss = getShortArray(v[0]);1818for (int i = 0; i < ss.length; i++) {1819System.out.println(" " + getString((short)table_scriptIDs[ss[i]]));1820}1821*/1822if (v.length == 1) {1823//the "allfonts" entries1824for (int i = 0; i < NUM_FONTS; i++) {1825table_sequences[k * NUM_FONTS + i] = v[0];1826}1827} else {1828for (int i = 0; i < NUM_FONTS; i++) {1829table_sequences[k * NUM_FONTS + i] = v[i];1830}1831}1832}1833//(4)1834head[INDEX_fontfileNameIDs] = (short)(head[INDEX_sequences] + table_sequences.length);1835table_fontfileNameIDs = toList(fontfileNameIDs);18361837//(5)1838head[INDEX_componentFontNameIDs] = (short)(head[INDEX_fontfileNameIDs] + table_fontfileNameIDs.length);1839table_componentFontNameIDs = toList(componentFontNameIDs);18401841//(6)componentFontNameID -> filenameID1842head[INDEX_filenames] = (short)(head[INDEX_componentFontNameIDs] + table_componentFontNameIDs.length);1843table_filenames = new short[table_componentFontNameIDs.length];1844Arrays.fill(table_filenames, (short) -1);18451846for (Entry<Short, Short> entry : filenames.entrySet()) {1847table_filenames[entry.getKey()] = entry.getValue();1848}18491850//(7)scriptID-> awtfontpath1851//the paths are stored as scriptID -> stringID in awtfontpahts1852head[INDEX_awtfontpaths] = (short)(head[INDEX_filenames] + table_filenames.length);1853table_awtfontpaths = new short[table_scriptIDs.length];1854for (Entry<Short, Short> entry : awtfontpaths.entrySet()) {1855table_awtfontpaths[entry.getKey()] = entry.getValue();1856}18571858//(8)exclusions1859head[INDEX_exclusions] = (short)(head[INDEX_awtfontpaths] + table_awtfontpaths.length);1860table_exclusions = new short[scriptIDs.size()];1861for (Entry<Short, int[]> entry : exclusions.entrySet()) {1862int[] exI = entry.getValue();1863char[] exC = new char[exI.length * 2];1864int j = 0;1865for (int i = 0; i < exI.length; i++) {1866exC[j++] = (char) (exI[i] >> 16);1867exC[j++] = (char) (exI[i] & 0xffff);1868}1869table_exclusions[entry.getKey()] = getStringID(new String (exC));1870}1871//(9)proportionals1872head[INDEX_proportionals] = (short)(head[INDEX_exclusions] + table_exclusions.length);1873table_proportionals = new short[proportionals.size() * 2];1874int j = 0;1875for (Entry<Short, Short> entry : proportionals.entrySet()) {1876table_proportionals[j++] = entry.getKey();1877table_proportionals[j++] = entry.getValue();1878}18791880//(10) see (1) for info, the only difference is "xxx.motif"1881head[INDEX_scriptFontsMotif] = (short)(head[INDEX_proportionals] + table_proportionals.length);1882if (scriptAllfontsMotif.size() != 0 || scriptFontsMotif.size() != 0) {1883len = table_scriptIDs.length + scriptFontsMotif.size() * 20;1884table_scriptFontsMotif = new short[len];18851886for (Entry<Short, Short> entry : scriptAllfontsMotif.entrySet()) {1887table_scriptFontsMotif[entry.getKey().intValue()] =1888(short)entry.getValue();1889}1890off = table_scriptIDs.length;1891for (Entry<Short, Short[]> entry : scriptFontsMotif.entrySet()) {1892table_scriptFontsMotif[entry.getKey().intValue()] = (short)-off;1893Short[] v = entry.getValue();1894int i = 0;1895while (i < 20) {1896if (v[i] != null) {1897table_scriptFontsMotif[off++] = v[i];1898} else {1899table_scriptFontsMotif[off++] = 0;1900}1901i++;1902}1903}1904} else {1905table_scriptFontsMotif = EMPTY_SHORT_ARRAY;1906}19071908//(11)short[] alphabeticSuffix1909head[INDEX_alphabeticSuffix] = (short)(head[INDEX_scriptFontsMotif] + table_scriptFontsMotif.length);1910table_alphabeticSuffix = new short[alphabeticSuffix.size() * 2];1911j = 0;1912for (Entry<Short, Short> entry : alphabeticSuffix.entrySet()) {1913table_alphabeticSuffix[j++] = entry.getKey();1914table_alphabeticSuffix[j++] = entry.getValue();1915}19161917//(15)short[] fallbackScriptIDs; just put the ID in head1918head[INDEX_fallbackScripts] = getShortArrayID(fallbackScriptIDs);19191920//(16)appendedfontpath1921head[INDEX_appendedfontpath] = getStringID(appendedfontpath);19221923//(17)version1924head[INDEX_version] = getStringID(version);19251926//(12)short[] StringIDs1927head[INDEX_stringIDs] = (short)(head[INDEX_alphabeticSuffix] + table_alphabeticSuffix.length);1928table_stringIDs = new short[stringIDNum + 1];1929System.arraycopy(stringIDs, 0, table_stringIDs, 0, stringIDNum + 1);19301931//(13)StringTable1932head[INDEX_stringTable] = (short)(head[INDEX_stringIDs] + stringIDNum + 1);1933table_stringTable = stringTable.toString().toCharArray();1934//(14)1935head[INDEX_TABLEEND] = (short)(head[INDEX_stringTable] + stringTable.length());19361937//StringTable cache1938stringCache = new String[table_stringIDs.length];1939}19401941//////////////////////////////////////////////1942private HashMap<String, Short> scriptIDs;1943//elc -> Encoding.Language.Country1944private HashMap<String, Short> elcIDs;1945//componentFontNameID starts from "1", "0" reserves for "undefined"1946private HashMap<String, Short> componentFontNameIDs;1947private HashMap<String, Short> fontfileNameIDs;1948private HashMap<String, Integer> logicalFontIDs;1949private HashMap<String, Integer> fontStyleIDs;19501951//componentFontNameID -> fontfileNameID1952private HashMap<Short, Short> filenames;19531954//elcID -> allfonts/logicalFont -> scriptID list1955//(1)if we have a "allfonts", then the length of the1956// value array is "1", otherwise it's 5, each font1957// must have their own individual entry.1958//scriptID list "short[]" is stored as an ID1959private HashMap<Short, short[]> sequences;19601961//scriptID ->logicFontID/fontStyleID->componentFontNameID,1962//a 20-entry array (5-name x 4-style) for each script1963private HashMap<Short, Short[]> scriptFonts;19641965//scriptID -> componentFontNameID1966private HashMap<Short, Short> scriptAllfonts;19671968//scriptID -> exclusionRanges[]1969private HashMap<Short, int[]> exclusions;19701971//scriptID -> fontpath1972private HashMap<Short, Short> awtfontpaths;19731974//fontID -> fontID1975private HashMap<Short, Short> proportionals;19761977//scriptID -> componentFontNameID1978private HashMap<Short, Short> scriptAllfontsMotif;19791980//scriptID ->logicFontID/fontStyleID->componentFontNameID,1981private HashMap<Short, Short[]> scriptFontsMotif;19821983//elcID -> stringID of alphabetic/XXXX1984private HashMap<Short, Short> alphabeticSuffix;19851986private short[] fallbackScriptIDs;1987private String version;1988private String appendedfontpath;19891990private void initLogicalNameStyle() {1991logicalFontIDs = new HashMap<String, Integer>();1992fontStyleIDs = new HashMap<String, Integer>();1993logicalFontIDs.put("serif", 0);1994logicalFontIDs.put("sansserif", 1);1995logicalFontIDs.put("monospaced", 2);1996logicalFontIDs.put("dialog", 3);1997logicalFontIDs.put("dialoginput",4);1998fontStyleIDs.put("plain", 0);1999fontStyleIDs.put("bold", 1);2000fontStyleIDs.put("italic", 2);2001fontStyleIDs.put("bolditalic", 3);2002}20032004private void initHashMaps() {2005scriptIDs = new HashMap<String, Short>();2006elcIDs = new HashMap<String, Short>();2007componentFontNameIDs = new HashMap<String, Short>();2008/*Init these tables to allow componentFontNameID, fontfileNameIDs2009to start from "1".2010*/2011componentFontNameIDs.put("", Short.valueOf((short)0));20122013fontfileNameIDs = new HashMap<String, Short>();2014filenames = new HashMap<Short, Short>();2015sequences = new HashMap<Short, short[]>();2016scriptFonts = new HashMap<Short, Short[]>();2017scriptAllfonts = new HashMap<Short, Short>();2018exclusions = new HashMap<Short, int[]>();2019awtfontpaths = new HashMap<Short, Short>();2020proportionals = new HashMap<Short, Short>();2021scriptFontsMotif = new HashMap<Short, Short[]>();2022scriptAllfontsMotif = new HashMap<Short, Short>();2023alphabeticSuffix = new HashMap<Short, Short>();2024fallbackScriptIDs = EMPTY_SHORT_ARRAY;2025/*2026version2027appendedfontpath2028*/2029}20302031private int[] parseExclusions(String key, String exclusions) {2032if (exclusions == null) {2033return EMPTY_INT_ARRAY;2034}2035// range format is xxxx-XXXX,yyyyyy-YYYYYY,.....2036int numExclusions = 1;2037int pos = 0;2038while ((pos = exclusions.indexOf(',', pos)) != -1) {2039numExclusions++;2040pos++;2041}2042int[] exclusionRanges = new int[numExclusions * 2];2043pos = 0;2044int newPos = 0;2045for (int j = 0; j < numExclusions * 2; ) {2046String lower, upper;2047int lo = 0, up = 0;2048try {2049newPos = exclusions.indexOf('-', pos);2050lower = exclusions.substring(pos, newPos);2051pos = newPos + 1;2052newPos = exclusions.indexOf(',', pos);2053if (newPos == -1) {2054newPos = exclusions.length();2055}2056upper = exclusions.substring(pos, newPos);2057pos = newPos + 1;2058int lowerLength = lower.length();2059int upperLength = upper.length();2060if (lowerLength != 4 && lowerLength != 62061|| upperLength != 4 && upperLength != 6) {2062throw new Exception();2063}2064lo = Integer.parseInt(lower, 16);2065up = Integer.parseInt(upper, 16);2066if (lo > up) {2067throw new Exception();2068}2069} catch (Exception e) {2070if (FontUtilities.debugFonts() &&2071logger != null) {2072logger.config("Failed parsing " + key +2073" property of font configuration.");20742075}2076return EMPTY_INT_ARRAY;2077}2078exclusionRanges[j++] = lo;2079exclusionRanges[j++] = up;2080}2081return exclusionRanges;2082}20832084private Short getID(HashMap<String, Short> map, String key) {2085Short ret = map.get(key);2086if ( ret == null) {2087map.put(key, (short)map.size());2088return map.get(key);2089}2090return ret;2091}20922093@SuppressWarnings("serial") // JDK-implementation class2094class FontProperties extends Properties {2095public synchronized Object put(Object k, Object v) {2096parseProperty((String)k, (String)v);2097return null;2098}2099}21002101private void parseProperty(String key, String value) {2102if (key.startsWith("filename.")) {2103//the only special case is "MingLiu_HKSCS" which has "_" in its2104//facename, we don't want to replace the "_" with " "2105key = key.substring(9);2106if (!"MingLiU_HKSCS".equals(key)) {2107key = key.replace('_', ' ');2108}2109Short faceID = getID(componentFontNameIDs, key);2110Short fileID = getID(fontfileNameIDs, value);2111//System.out.println("faceID=" + faceID + "/" + key + " -> "2112// + "fileID=" + fileID + "/" + value);2113filenames.put(faceID, fileID);2114} else if (key.startsWith("exclusion.")) {2115key = key.substring(10);2116exclusions.put(getID(scriptIDs,key), parseExclusions(key,value));2117} else if (key.startsWith("sequence.")) {2118key = key.substring(9);2119boolean hasDefault = false;2120boolean has1252 = false;21212122//get the scriptID list2123String[] ss = splitSequence(value).toArray(EMPTY_STRING_ARRAY);2124short [] sa = new short[ss.length];2125for (int i = 0; i < ss.length; i++) {2126if ("alphabetic/default".equals(ss[i])) {2127//System.out.println(key + " -> " + ss[i]);2128ss[i] = "alphabetic";2129hasDefault = true;2130} else if ("alphabetic/1252".equals(ss[i])) {2131//System.out.println(key + " -> " + ss[i]);2132ss[i] = "alphabetic";2133has1252 = true;2134}2135sa[i] = getID(scriptIDs, ss[i]).shortValue();2136//System.out.println("scriptID=" + si[i] + "/" + ss[i]);2137}2138//convert the "short[] -> string -> stringID"2139short scriptArrayID = getShortArrayID(sa);2140Short elcID = null;2141int dot = key.indexOf('.');2142if (dot == -1) {2143if ("fallback".equals(key)) {2144fallbackScriptIDs = sa;2145return;2146}2147if ("allfonts".equals(key)) {2148elcID = getID(elcIDs, "NULL.NULL.NULL");2149} else {2150if (logger != null) {2151logger.config("Error sequence def: <sequence." + key + ">");2152}2153return;2154}2155} else {2156elcID = getID(elcIDs, key.substring(dot + 1));2157//System.out.println("elcID=" + elcID + "/" + key.substring(dot + 1));2158key = key.substring(0, dot);2159}2160short[] scriptArrayIDs = null;2161if ("allfonts".equals(key)) {2162scriptArrayIDs = new short[1];2163scriptArrayIDs[0] = scriptArrayID;2164} else {2165scriptArrayIDs = sequences.get(elcID);2166if (scriptArrayIDs == null) {2167scriptArrayIDs = new short[5];2168}2169Integer fid = logicalFontIDs.get(key);2170if (fid == null) {2171if (logger != null) {2172logger.config("Unrecognizable logicfont name " + key);2173}2174return;2175}2176//System.out.println("sequence." + key + "/" + id);2177scriptArrayIDs[fid.intValue()] = scriptArrayID;2178}2179sequences.put(elcID, scriptArrayIDs);2180if (hasDefault) {2181alphabeticSuffix.put(elcID, getStringID("default"));2182} else2183if (has1252) {2184alphabeticSuffix.put(elcID, getStringID("1252"));2185}2186} else if (key.startsWith("allfonts.")) {2187key = key.substring(9);2188if (key.endsWith(".motif")) {2189key = key.substring(0, key.length() - 6);2190//System.out.println("motif: all." + key + "=" + value);2191scriptAllfontsMotif.put(getID(scriptIDs,key), getID(componentFontNameIDs,value));2192} else {2193scriptAllfonts.put(getID(scriptIDs,key), getID(componentFontNameIDs,value));2194}2195} else if (key.startsWith("awtfontpath.")) {2196key = key.substring(12);2197//System.out.println("scriptID=" + getID(scriptIDs, key) + "/" + key);2198awtfontpaths.put(getID(scriptIDs, key), getStringID(value));2199} else if ("version".equals(key)) {2200version = value;2201} else if ("appendedfontpath".equals(key)) {2202appendedfontpath = value;2203} else if (key.startsWith("proportional.")) {2204key = key.substring(13).replace('_', ' ');2205//System.out.println(key + "=" + value);2206proportionals.put(getID(componentFontNameIDs, key),2207getID(componentFontNameIDs, value));2208} else {2209//"name.style.script(.motif)", we don't care anything else2210int dot1, dot2;2211boolean isMotif = false;22122213dot1 = key.indexOf('.');2214if (dot1 == -1) {2215if (logger != null) {2216logger.config("Failed parsing " + key +2217" property of font configuration.");22182219}2220return;2221}2222dot2 = key.indexOf('.', dot1 + 1);2223if (dot2 == -1) {2224if (logger != null) {2225logger.config("Failed parsing " + key +2226" property of font configuration.");22272228}2229return;2230}2231if (key.endsWith(".motif")) {2232key = key.substring(0, key.length() - 6);2233isMotif = true;2234//System.out.println("motif: " + key + "=" + value);2235}2236Integer nameID = logicalFontIDs.get(key.substring(0, dot1));2237Integer styleID = fontStyleIDs.get(key.substring(dot1+1, dot2));2238Short scriptID = getID(scriptIDs, key.substring(dot2 + 1));2239if (nameID == null || styleID == null) {2240if (logger != null) {2241logger.config("unrecognizable logicfont name/style at " + key);2242}2243return;2244}2245Short[] pnids;2246if (isMotif) {2247pnids = scriptFontsMotif.get(scriptID);2248} else {2249pnids = scriptFonts.get(scriptID);2250}2251if (pnids == null) {2252pnids = new Short[20];2253}2254pnids[nameID.intValue() * NUM_STYLES + styleID.intValue()]2255= getID(componentFontNameIDs, value);2256/*2257System.out.println("key=" + key + "/<" + nameID + "><" + styleID2258+ "><" + scriptID + ">=" + value2259+ "/" + getID(componentFontNameIDs, value));2260*/2261if (isMotif) {2262scriptFontsMotif.put(scriptID, pnids);2263} else {2264scriptFonts.put(scriptID, pnids);2265}2266}2267}2268}2269}227022712272