Path: blob/master/src/java.desktop/share/classes/sun/awt/FontConfiguration.java
66645 views
/*1* Copyright (c) 1996, 2022, 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.") &&966!charsetName.equals("default") &&967!charsetName.startsWith("sun.font.")) {968fc = Charset.forName(charsetName);969} else {970@SuppressWarnings("removal")971Class<?> fcc = AccessController.doPrivileged(new PrivilegedAction<Class<?>>() {972public Class<?> run() {973try {974return Class.forName(charsetName, true,975ClassLoader.getSystemClassLoader());976} catch (ClassNotFoundException e) {977}978return null;979}980});981982if (fcc != null) {983try {984fc = (Charset) fcc.getDeclaredConstructor().newInstance();985} catch (Exception e) {986}987}988}989if (fc == null) {990fc = getDefaultFontCharset(fontName);991}992993if (charsetName.equals("default")){994charsetRegistry.put(fontName, fc);995} else {996charsetRegistry.put(charsetName, fc);997}998return fc.newEncoder();999}10001001protected abstract Charset getDefaultFontCharset(1002String fontName);10031004/* This retrieves the platform font directories (path) calculated1005* by setAWTFontPathSequence(String[]). The default implementation1006* returns null, its expected that X11 platforms may return1007* non-null.1008*/1009public HashSet<String> getAWTFontPathSet() {1010return null;1011}10121013////////////////////////////////////////////////////////////////////////1014// methods for extracting information from the fontconfig data for 2D //1015////////////////////////////////////////////////////////////////////////10161017/**1018* Returns an array of composite font descriptors for all logical font1019* faces.1020*/1021public CompositeFontDescriptor[] get2DCompositeFontInfo() {1022CompositeFontDescriptor[] result =1023new CompositeFontDescriptor[NUM_FONTS * NUM_STYLES];1024String defaultFontFile = fontManager.getDefaultFontFile();1025String defaultFontFaceName = fontManager.getDefaultFontFaceName();10261027for (int fontIndex = 0; fontIndex < NUM_FONTS; fontIndex++) {1028String fontName = publicFontNames[fontIndex];10291030// determine exclusion ranges for font1031// AWT uses separate exclusion range array per component font.1032// 2D packs all range boundaries into one array.1033// Both use separate entries for lower and upper boundary.1034int[][] exclusions = compExclusions[fontIndex];1035int numExclusionRanges = 0;1036for (int i = 0; i < exclusions.length; i++) {1037numExclusionRanges += exclusions[i].length;1038}1039int[] exclusionRanges = new int[numExclusionRanges];1040int[] exclusionRangeLimits = new int[exclusions.length];1041int exclusionRangeIndex = 0;1042int exclusionRangeLimitIndex = 0;1043for (int i = 0; i < exclusions.length; i++) {1044int[] componentRanges = exclusions[i];1045for (int j = 0; j < componentRanges.length; ) {1046int value = componentRanges[j];1047exclusionRanges[exclusionRangeIndex++] = componentRanges[j++];1048exclusionRanges[exclusionRangeIndex++] = componentRanges[j++];1049}1050exclusionRangeLimits[i] = exclusionRangeIndex;1051}1052// other info is per style1053for (int styleIndex = 0; styleIndex < NUM_STYLES; styleIndex++) {1054int maxComponentFontCount = compFontNameIDs[fontIndex][styleIndex].length;1055// fall back fonts listed in the lib/fonts/fallback directory1056if (installedFallbackFontFiles != null) {1057maxComponentFontCount += installedFallbackFontFiles.length;1058}1059String faceName = fontName + "." + styleNames[styleIndex];10601061// determine face names and file names of component fonts1062String[] componentFaceNames = new String[maxComponentFontCount];1063String[] componentFileNames = new String[maxComponentFontCount];10641065int index;1066for (index = 0; index < compFontNameIDs[fontIndex][styleIndex].length; index++) {1067short fontNameID = compFontNameIDs[fontIndex][styleIndex][index];1068short fileNameID = getComponentFileID(fontNameID);1069componentFaceNames[index] = getFaceNameFromComponentFontName(getComponentFontName(fontNameID));1070componentFileNames[index] = mapFileName(getComponentFileName(fileNameID));1071if (componentFileNames[index] == null ||1072needToSearchForFile(componentFileNames[index])) {1073componentFileNames[index] = getFileNameFromComponentFontName(getComponentFontName(fontNameID));1074}1075/*1076System.out.println(publicFontNames[fontIndex] + "." + styleNames[styleIndex] + "."1077+ getString(table_scriptIDs[coreScripts[index]]) + "=" + componentFileNames[index]);1078*/1079}10801081if (installedFallbackFontFiles != null) {1082for (int ifb=0; ifb<installedFallbackFontFiles.length; ifb++) {1083componentFaceNames[index] = null;1084componentFileNames[index] = installedFallbackFontFiles[ifb];1085index++;1086}1087}10881089if (index < maxComponentFontCount) {1090String[] newComponentFaceNames = new String[index];1091System.arraycopy(componentFaceNames, 0, newComponentFaceNames, 0, index);1092componentFaceNames = newComponentFaceNames;1093String[] newComponentFileNames = new String[index];1094System.arraycopy(componentFileNames, 0, newComponentFileNames, 0, index);1095componentFileNames = newComponentFileNames;1096}1097// exclusion range limit array length must match component face name1098// array length - native code relies on this10991100int[] clippedExclusionRangeLimits = exclusionRangeLimits;1101if (index != clippedExclusionRangeLimits.length) {1102int len = exclusionRangeLimits.length;1103clippedExclusionRangeLimits = new int[index];1104System.arraycopy(exclusionRangeLimits, 0, clippedExclusionRangeLimits, 0, len);1105//padding for various fallback fonts1106for (int i = len; i < index; i++) {1107clippedExclusionRangeLimits[i] = exclusionRanges.length;1108}1109}1110/*1111System.out.println(faceName + ":");1112for (int i = 0; i < componentFileNames.length; i++) {1113System.out.println(" " + componentFaceNames[i]1114+ " -> " + componentFileNames[i]);1115}1116*/1117result[fontIndex * NUM_STYLES + styleIndex]1118= new CompositeFontDescriptor(1119faceName,1120compCoreNum[fontIndex],1121componentFaceNames,1122componentFileNames,1123exclusionRanges,1124clippedExclusionRangeLimits);1125}1126}1127return result;1128}11291130protected abstract String getFaceNameFromComponentFontName(String componentFontName);1131protected abstract String getFileNameFromComponentFontName(String componentFontName);11321133/*1134public class 2dFont {1135public String platformName;1136public String fontfileName;1137}1138private 2dFont [] componentFonts = null;1139*/11401141/* Used on Linux to test if a file referenced in a font configuration1142* file exists in the location that is expected. If it does, no need1143* to search for it. If it doesn't then unless its a fallback font,1144* return that expensive code should be invoked to search for the font.1145*/1146HashMap<String, Boolean> existsMap;1147public boolean needToSearchForFile(String fileName) {1148if (!FontUtilities.isLinux) {1149return false;1150} else if (existsMap == null) {1151existsMap = new HashMap<String, Boolean>();1152}1153Boolean exists = existsMap.get(fileName);1154if (exists == null) {1155/* call getNumberCoreFonts() to ensure these are initialised, and1156* if this file isn't for a core component, ie, is a for a fallback1157* font which very typically isn't available, then can't afford1158* to take the start-up penalty to search for it.1159*/1160getNumberCoreFonts();1161if (!coreFontFileNames.contains(fileName)) {1162exists = Boolean.TRUE;1163} else {1164exists = Boolean.valueOf((new File(fileName)).exists());1165existsMap.put(fileName, exists);1166if (FontUtilities.debugFonts() &&1167exists == Boolean.FALSE) {1168logger.warning("Couldn't locate font file " + fileName);1169}1170}1171}1172return exists == Boolean.FALSE;1173}11741175private int numCoreFonts = -1;1176private String[] componentFonts = null;1177HashMap <String, String> filenamesMap = new HashMap<String, String>();1178HashSet <String> coreFontFileNames = new HashSet<String>();11791180/* Return the number of core fonts. Note this isn't thread safe but1181* a calling thread can call this and getPlatformFontNames() in either1182* order.1183*/1184public int getNumberCoreFonts() {1185if (numCoreFonts == -1) {1186numCoreFonts = coreFontNameIDs.size();1187Short[] emptyShortArray = new Short[0];1188Short[] core = coreFontNameIDs.toArray(emptyShortArray);1189Short[] fallback = fallbackFontNameIDs.toArray(emptyShortArray);11901191int numFallbackFonts = 0;1192int i;1193for (i = 0; i < fallback.length; i++) {1194if (coreFontNameIDs.contains(fallback[i])) {1195fallback[i] = null;1196continue;1197}1198numFallbackFonts++;1199}1200componentFonts = new String[numCoreFonts + numFallbackFonts];1201String filename = null;1202for (i = 0; i < core.length; i++) {1203short fontid = core[i];1204short fileid = getComponentFileID(fontid);1205componentFonts[i] = getComponentFontName(fontid);1206String compFileName = getComponentFileName(fileid);1207if (compFileName != null) {1208coreFontFileNames.add(compFileName);1209}1210filenamesMap.put(componentFonts[i], mapFileName(compFileName));1211}1212for (int j = 0; j < fallback.length; j++) {1213if (fallback[j] != null) {1214short fontid = fallback[j];1215short fileid = getComponentFileID(fontid);1216componentFonts[i] = getComponentFontName(fontid);1217filenamesMap.put(componentFonts[i],1218mapFileName(getComponentFileName(fileid)));1219i++;1220}1221}1222}1223return numCoreFonts;1224}12251226/* Return all platform font names used by this font configuration.1227* The first getNumberCoreFonts() entries are guaranteed to be the1228* core fonts - ie no fall back only fonts.1229*/1230public String[] getPlatformFontNames() {1231if (numCoreFonts == -1) {1232getNumberCoreFonts();1233}1234return componentFonts;1235}12361237/**1238* Returns a file name for the physical font represented by this platform font name,1239* if the font configuration has such information available, or null if the1240* information is unavailable. The file name returned is just a hint; a null return1241* value doesn't necessarily mean that the font is unavailable, nor does a non-null1242* return value guarantee that the file exists and contains the physical font.1243* The file name can be an absolute or a relative path name.1244*/1245public String getFileNameFromPlatformName(String platformName) {1246// get2DCompositeFontInfo1247// -> getFileNameFromComponentfontName() (W/M)1248// -> getFileNameFromPlatformName()1249// it's a waste of time on Win32, but I have to give X11 a chance to1250// call getFileNameFromXLFD()1251return filenamesMap.get(platformName);1252}12531254/**1255* Returns a configuration specific path to be appended to the font1256* search path.1257*/1258public String getExtraFontPath() {1259return getString(head[INDEX_appendedfontpath]);1260}12611262public String getVersion() {1263return getString(head[INDEX_version]);1264}12651266/* subclass support */1267protected static FontConfiguration getFontConfiguration() {1268return fontConfig;1269}12701271protected void setFontConfiguration() {1272fontConfig = this; /* static initialization */1273}12741275//////////////////////////////////////////////////////////////////////1276// FontConfig data tables and the index constants in binary file //1277//////////////////////////////////////////////////////////////////////1278/* The binary font configuration file begins with a short[] "head", which1279* contains the offsets to the starts of the individual data table which1280* immediately follow. The current implementation includes the tables shown1281* below.1282*1283* (00) table_scriptIDs :stringIDs of all defined CharacterSubsetNames1284* (01) table_scriptFonts :scriptID x fontIndex x styleIndex->1285* PlatformFontNameID mapping. Each scriptID might1286* have 1 or 20 entries depends on if it is defined1287* via a "allfonts.CharacterSubsetname" or a list of1288* "LogicalFontName.StyleName.CharacterSubsetName"1289* entries, positive entry means it's a "allfonts"1290* entry, a negative value means this is a offset to1291* a NUM_FONTS x NUM_STYLES subtable.1292* (02) table_elcIDs :stringIDs of all defined ELC names, string1293* "NULL.NULL.NULL" is used for "default"1294* (03) table_sequences :elcID x logicalFont -> scriptIDs table defined1295* by "sequence.allfonts/LogicalFontName.ELC" in1296* font configuration file, each "elcID" has1297* NUM_FONTS (5) entries in this table.1298* (04) table_fontfileNameIDs1299* :stringIDs of all defined font file names1300* (05) table_componentFontNameIDs1301* :stringIDs of all defined PlatformFontNames1302* (06) table_filenames :platformFontNamesID->fontfileNameID mapping1303* table, the index is the platformFontNamesID.1304* (07) table_awtfontpaths :CharacterSubsetNames->awtfontpaths mapping table,1305* the index is the CharacterSubsetName's stringID1306* and content is the stringID of awtfontpath.1307* (08) table_exclusions :scriptID -> exclusionRanges mapping table,1308* the index is the scriptID and the content is1309a id of an exclusionRanges int[].1310* (09) table_proportionals:list of pairs of PlatformFontNameIDs, stores1311* the replacement info defined by "proportional"1312* keyword.1313* (10) table_scriptFontsMotif1314* :same as (01) except this table stores the1315* info defined with ".motif" keyword1316* (11) table_alphabeticSuffix1317* :elcID -> stringID of alphabetic/XXXX entries1318* (12) table_stringIDs :The index of this table is the string ID, the1319* content is the "start index" of this string in1320* stringTable, use the start index of next entry1321* as the "end index".1322* (13) table_stringTable :The real storage of all character strings defined1323* /used this font configuration, need a pair of1324* "start" and "end" indices to access.1325* (14) reserved1326* (15) table_fallbackScripts1327* :stringIDs of fallback CharacterSubsetnames, stored1328* in the order of they are defined in sequence.fallback.1329* (16) table_appendedfontpath1330* :stringtID of the "appendedfontpath" defined.1331* (17) table_version :stringID of the version number of this fontconfig file.1332*/1333private static final int HEAD_LENGTH = 20;1334private static final int INDEX_scriptIDs = 0;1335private static final int INDEX_scriptFonts = 1;1336private static final int INDEX_elcIDs = 2;1337private static final int INDEX_sequences = 3;1338private static final int INDEX_fontfileNameIDs = 4;1339private static final int INDEX_componentFontNameIDs = 5;1340private static final int INDEX_filenames = 6;1341private static final int INDEX_awtfontpaths = 7;1342private static final int INDEX_exclusions = 8;1343private static final int INDEX_proportionals = 9;1344private static final int INDEX_scriptFontsMotif = 10;1345private static final int INDEX_alphabeticSuffix = 11;1346private static final int INDEX_stringIDs = 12;1347private static final int INDEX_stringTable = 13;1348private static final int INDEX_TABLEEND = 14;1349private static final int INDEX_fallbackScripts = 15;1350private static final int INDEX_appendedfontpath = 16;1351private static final int INDEX_version = 17;13521353private static short[] head;1354private static short[] table_scriptIDs;1355private static short[] table_scriptFonts;1356private static short[] table_elcIDs;1357private static short[] table_sequences;1358private static short[] table_fontfileNameIDs;1359private static short[] table_componentFontNameIDs;1360private static short[] table_filenames;1361protected static short[] table_awtfontpaths;1362private static short[] table_exclusions;1363private static short[] table_proportionals;1364private static short[] table_scriptFontsMotif;1365private static short[] table_alphabeticSuffix;1366private static short[] table_stringIDs;1367private static char[] table_stringTable;13681369/**1370* Checks consistencies of complied fontconfig data. This method1371* is called only at the build-time from1372* build.tools.compilefontconfig.CompileFontConfig.1373*/1374private static void sanityCheck() {1375int errors = 0;13761377//This method will only be called during build time, do we1378//need do PrivilegedAction?1379@SuppressWarnings("removal")1380String osName = java.security.AccessController.doPrivileged(1381new java.security.PrivilegedAction<String>() {1382public String run() {1383return System.getProperty("os.name");1384}1385});13861387//componentFontNameID starts from "1"1388for (int ii = 1; ii < table_filenames.length; ii++) {1389if (table_filenames[ii] == -1) {1390// The corresponding finename entry for a component1391// font name is mandatory on Windows, but it's1392// optional on Solaris and Linux.1393if (osName.contains("Windows")) {1394System.err.println("\n Error: <filename."1395+ getString(table_componentFontNameIDs[ii])1396+ "> entry is missing!!!");1397errors++;1398} else {1399if (verbose && !isEmpty(table_filenames)) {1400System.err.println("\n Note: 'filename' entry is undefined for \""1401+ getString(table_componentFontNameIDs[ii])1402+ "\"");1403}1404}1405}1406}1407for (int ii = 0; ii < table_scriptIDs.length; ii++) {1408short fid = table_scriptFonts[ii];1409if (fid == 0) {1410System.out.println("\n Error: <allfonts."1411+ getString(table_scriptIDs[ii])1412+ "> entry is missing!!!");1413errors++;1414continue;1415} else if (fid < 0) {1416fid = (short)-fid;1417for (int iii = 0; iii < NUM_FONTS; iii++) {1418for (int iij = 0; iij < NUM_STYLES; iij++) {1419int jj = iii * NUM_STYLES + iij;1420short ffid = table_scriptFonts[fid + jj];1421if (ffid == 0) {1422System.err.println("\n Error: <"1423+ getFontName(iii) + "."1424+ getStyleName(iij) + "."1425+ getString(table_scriptIDs[ii])1426+ "> entry is missing!!!");1427errors++;1428}1429}1430}1431}1432}1433if (errors != 0) {1434System.err.println("!!THERE ARE " + errors + " ERROR(S) IN "1435+ "THE FONTCONFIG FILE, PLEASE CHECK ITS CONTENT!!\n");1436System.exit(1);1437}1438}14391440private static boolean isEmpty(short[] a) {1441for (short s : a) {1442if (s != -1) {1443return false;1444}1445}1446return true;1447}14481449//dump the fontconfig data tables1450private static void dump() {1451System.out.println("\n----Head Table------------");1452for (int ii = 0; ii < HEAD_LENGTH; ii++) {1453System.out.println(" " + ii + " : " + head[ii]);1454}1455System.out.println("\n----scriptIDs-------------");1456printTable(table_scriptIDs, 0);1457System.out.println("\n----scriptFonts----------------");1458for (int ii = 0; ii < table_scriptIDs.length; ii++) {1459short fid = table_scriptFonts[ii];1460if (fid >= 0) {1461System.out.println(" allfonts."1462+ getString(table_scriptIDs[ii])1463+ "="1464+ getString(table_componentFontNameIDs[fid]));1465}1466}1467for (int ii = 0; ii < table_scriptIDs.length; ii++) {1468short fid = table_scriptFonts[ii];1469if (fid < 0) {1470fid = (short)-fid;1471for (int iii = 0; iii < NUM_FONTS; iii++) {1472for (int iij = 0; iij < NUM_STYLES; iij++) {1473int jj = iii * NUM_STYLES + iij;1474short ffid = table_scriptFonts[fid + jj];1475System.out.println(" "1476+ getFontName(iii) + "."1477+ getStyleName(iij) + "."1478+ getString(table_scriptIDs[ii])1479+ "="1480+ getString(table_componentFontNameIDs[ffid]));1481}1482}14831484}1485}1486System.out.println("\n----elcIDs----------------");1487printTable(table_elcIDs, 0);1488System.out.println("\n----sequences-------------");1489for (int ii = 0; ii< table_elcIDs.length; ii++) {1490System.out.println(" " + ii + "/" + getString(table_elcIDs[ii]));1491short[] ss = getShortArray(table_sequences[ii * NUM_FONTS + 0]);1492for (int jj = 0; jj < ss.length; jj++) {1493System.out.println(" " + getString(table_scriptIDs[ss[jj]]));1494}1495}1496System.out.println("\n----fontfileNameIDs-------");1497printTable(table_fontfileNameIDs, 0);14981499System.out.println("\n----componentFontNameIDs--");1500printTable(table_componentFontNameIDs, 1);1501System.out.println("\n----filenames-------------");1502for (int ii = 0; ii < table_filenames.length; ii++) {1503if (table_filenames[ii] == -1) {1504System.out.println(" " + ii + " : null");1505} else {1506System.out.println(" " + ii + " : "1507+ getString(table_fontfileNameIDs[table_filenames[ii]]));1508}1509}1510System.out.println("\n----awtfontpaths---------");1511for (int ii = 0; ii < table_awtfontpaths.length; ii++) {1512System.out.println(" " + getString(table_scriptIDs[ii])1513+ " : "1514+ getString(table_awtfontpaths[ii]));1515}1516System.out.println("\n----proportionals--------");1517for (int ii = 0; ii < table_proportionals.length; ii++) {1518System.out.println(" "1519+ getString(table_componentFontNameIDs[table_proportionals[ii++]])1520+ " -> "1521+ getString(table_componentFontNameIDs[table_proportionals[ii]]));1522}1523int i = 0;1524System.out.println("\n----alphabeticSuffix----");1525while (i < table_alphabeticSuffix.length) {1526System.out.println(" " + getString(table_elcIDs[table_alphabeticSuffix[i++]])1527+ " -> " + getString(table_alphabeticSuffix[i++]));1528}1529System.out.println("\n----String Table---------");1530System.out.println(" stringID: Num =" + table_stringIDs.length);1531System.out.println(" stringTable: Size=" + table_stringTable.length * 2);15321533System.out.println("\n----fallbackScriptIDs---");1534short[] fbsIDs = getShortArray(head[INDEX_fallbackScripts]);1535for (int ii = 0; ii < fbsIDs.length; ii++) {1536System.out.println(" " + getString(table_scriptIDs[fbsIDs[ii]]));1537}1538System.out.println("\n----appendedfontpath-----");1539System.out.println(" " + getString(head[INDEX_appendedfontpath]));1540System.out.println("\n----Version--------------");1541System.out.println(" " + getString(head[INDEX_version]));1542}154315441545//////////////////////////////////////////////////////////////////////1546// Data table access methods //1547//////////////////////////////////////////////////////////////////////15481549/* Return the fontID of the platformFontName defined in this font config1550* by "LogicalFontName.StyleName.CharacterSubsetName" entry or1551* "allfonts.CharacterSubsetName" entry in properties format fc file.1552*/1553protected static short getComponentFontID(short scriptID, int fontIndex, int styleIndex) {1554short fid = table_scriptFonts[scriptID];1555//System.out.println("fid=" + fid + "/ scriptID=" + scriptID + ", fi=" + fontIndex + ", si=" + styleIndex);1556if (fid >= 0) {1557//"allfonts"1558return fid;1559} else {1560return table_scriptFonts[-fid + fontIndex * NUM_STYLES + styleIndex];1561}1562}15631564/* Same as getCompoentFontID() except this method returns the fontID define by1565* "xxxx.motif" entry.1566*/1567protected static short getComponentFontIDMotif(short scriptID, int fontIndex, int styleIndex) {1568if (table_scriptFontsMotif.length == 0) {1569return 0;1570}1571short fid = table_scriptFontsMotif[scriptID];1572if (fid >= 0) {1573//"allfonts" > 0 or "not defined" == 01574return fid;1575} else {1576return table_scriptFontsMotif[-fid + fontIndex * NUM_STYLES + styleIndex];1577}1578}15791580private static int[] getExclusionRanges(short scriptID) {1581short exID = table_exclusions[scriptID];1582if (exID == 0) {1583return EMPTY_INT_ARRAY;1584} else {1585char[] exChar = getString(exID).toCharArray();1586int[] exInt = new int[exChar.length / 2];1587int i = 0;1588for (int j = 0; j < exInt.length; j++) {1589exInt[j] = (exChar[i++] << 16) + (exChar[i++] & 0xffff);1590}1591return exInt;1592}1593}15941595private static boolean contains(short[] IDs, short id, int limit) {1596for (int i = 0; i < limit; i++) {1597if (IDs[i] == id) {1598return true;1599}1600}1601return false;1602}16031604/* Return the PlatformFontName from its fontID*/1605protected static String getComponentFontName(short id) {1606if (id < 0) {1607return null;1608}1609return getString(table_componentFontNameIDs[id]);1610}16111612private static String getComponentFileName(short id) {1613if (id < 0) {1614return null;1615}1616return getString(table_fontfileNameIDs[id]);1617}16181619//componentFontID -> componentFileID1620private static short getComponentFileID(short nameID) {1621return table_filenames[nameID];1622}16231624private static String getScriptName(short scriptID) {1625return getString(table_scriptIDs[scriptID]);1626}16271628private HashMap<String, Short> reorderScripts;1629protected short[] getCoreScripts(int fontIndex) {1630short elc = getInitELC();1631/*1632System.out.println("getCoreScripts: elc=" + elc + ", fontIndex=" + fontIndex);1633short[] ss = getShortArray(table_sequences[elc * NUM_FONTS + fontIndex]);1634for (int i = 0; i < ss.length; i++) {1635System.out.println(" " + getString((short)table_scriptIDs[ss[i]]));1636}1637*/1638short[] scripts = getShortArray(table_sequences[elc * NUM_FONTS + fontIndex]);1639if (preferLocaleFonts) {1640if (reorderScripts == null) {1641reorderScripts = new HashMap<String, Short>();1642}1643String[] ss = new String[scripts.length];1644for (int i = 0; i < ss.length; i++) {1645ss[i] = getScriptName(scripts[i]);1646reorderScripts.put(ss[i], scripts[i]);1647}1648reorderSequenceForLocale(ss);1649for (int i = 0; i < ss.length; i++) {1650scripts[i] = reorderScripts.get(ss[i]);1651}1652}1653return scripts;1654}16551656private static short[] getFallbackScripts() {1657return getShortArray(head[INDEX_fallbackScripts]);1658}16591660private static void printTable(short[] list, int start) {1661for (int i = start; i < list.length; i++) {1662System.out.println(" " + i + " : " + getString(list[i]));1663}1664}16651666private static short[] readShortTable(DataInputStream in, int len )1667throws IOException {1668if (len == 0) {1669return EMPTY_SHORT_ARRAY;1670}1671short[] data = new short[len];1672byte[] bb = new byte[len * 2];1673in.read(bb);1674int i = 0,j = 0;1675while (i < len) {1676data[i++] = (short)(bb[j++] << 8 | (bb[j++] & 0xff));1677}1678return data;1679}16801681private static void writeShortTable(DataOutputStream out, short[] data)1682throws IOException {1683for (short val : data) {1684out.writeShort(val);1685}1686}16871688private static short[] toList(HashMap<String, Short> map) {1689short[] list = new short[map.size()];1690Arrays.fill(list, (short) -1);1691for (Entry<String, Short> entry : map.entrySet()) {1692list[entry.getValue()] = getStringID(entry.getKey());1693}1694return list;1695}16961697//runtime cache1698private static String[] stringCache;1699protected static String getString(short stringID) {1700if (stringID == 0)1701return null;1702/*1703if (loadingProperties) {1704return stringTable.substring(stringIDs[stringID],1705stringIDs[stringID+1]);1706}1707*/1708//sync if we want it to be MT-enabled1709if (stringCache[stringID] == null){1710stringCache[stringID] =1711new String (table_stringTable,1712table_stringIDs[stringID],1713table_stringIDs[stringID+1] - table_stringIDs[stringID]);1714}1715return stringCache[stringID];1716}17171718private static short[] getShortArray(short shortArrayID) {1719String s = getString(shortArrayID);1720char[] cc = s.toCharArray();1721short[] ss = new short[cc.length];1722for (int i = 0; i < cc.length; i++) {1723ss[i] = (short)(cc[i] & 0xffff);1724}1725return ss;1726}17271728private static short getStringID(String s) {1729if (s == null) {1730return (short)0;1731}1732short pos0 = (short)stringTable.length();1733stringTable.append(s);1734short pos1 = (short)stringTable.length();17351736stringIDs[stringIDNum] = pos0;1737stringIDs[stringIDNum + 1] = pos1;1738stringIDNum++;1739if (stringIDNum + 1 >= stringIDs.length) {1740short[] tmp = new short[stringIDNum + 1000];1741System.arraycopy(stringIDs, 0, tmp, 0, stringIDNum);1742stringIDs = tmp;1743}1744return (short)(stringIDNum - 1);1745}17461747private static short getShortArrayID(short[] sa) {1748char[] cc = new char[sa.length];1749for (int i = 0; i < sa.length; i ++) {1750cc[i] = (char)sa[i];1751}1752String s = new String(cc);1753return getStringID(s);1754}17551756//utility "empty" objects1757private static final int[] EMPTY_INT_ARRAY = new int[0];1758private static final String[] EMPTY_STRING_ARRAY = new String[0];1759private static final short[] EMPTY_SHORT_ARRAY = new short[0];1760private static final String UNDEFINED_COMPONENT_FONT = "unknown";17611762//////////////////////////////////////////////////////////////////////////1763//Convert the FontConfig data in Properties file to binary data tables //1764//////////////////////////////////////////////////////////////////////////1765static class PropertiesHandler {1766public void load(InputStream in) throws IOException {1767initLogicalNameStyle();1768initHashMaps();1769FontProperties fp = new FontProperties();1770fp.load(in);1771initBinaryTable();1772}17731774private void initBinaryTable() {1775//(0)1776head = new short[HEAD_LENGTH];1777head[INDEX_scriptIDs] = (short)HEAD_LENGTH;17781779table_scriptIDs = toList(scriptIDs);1780//(1)a: scriptAllfonts scriptID/allfonts -> componentFontNameID1781// b: scriptFonts scriptID -> componentFontNameID[20]1782//if we have a "allfonts.script" def, then we just put1783//the "-platformFontID" value in the slot, otherwise the slot1784//value is "offset" which "offset" is where 20 entries located1785//in the table attached.1786head[INDEX_scriptFonts] = (short)(head[INDEX_scriptIDs] + table_scriptIDs.length);1787int len = table_scriptIDs.length + scriptFonts.size() * 20;1788table_scriptFonts = new short[len];17891790for (Entry<Short, Short> entry : scriptAllfonts.entrySet()) {1791table_scriptFonts[entry.getKey().intValue()] = entry.getValue();1792}1793int off = table_scriptIDs.length;1794for (Entry<Short, Short[]> entry : scriptFonts.entrySet()) {1795table_scriptFonts[entry.getKey().intValue()] = (short)-off;1796Short[] v = entry.getValue();1797for (int i = 0; i < 20; i++) {1798if (v[i] != null) {1799table_scriptFonts[off++] = v[i];1800} else {1801table_scriptFonts[off++] = 0;1802}1803}1804}18051806//(2)1807head[INDEX_elcIDs] = (short)(head[INDEX_scriptFonts] + table_scriptFonts.length);1808table_elcIDs = toList(elcIDs);18091810//(3) sequences elcID -> XXXX[1|5] -> scriptID[]1811head[INDEX_sequences] = (short)(head[INDEX_elcIDs] + table_elcIDs.length);1812table_sequences = new short[elcIDs.size() * NUM_FONTS];1813for (Entry<Short, short[]> entry : sequences.entrySet()) {1814//table_sequences[entry.getKey().intValue()] = (short)-off;1815int k = entry.getKey().intValue();1816short[] v = entry.getValue();1817/*1818System.out.println("elc=" + k + "/" + getString((short)table_elcIDs[k]));1819short[] ss = getShortArray(v[0]);1820for (int i = 0; i < ss.length; i++) {1821System.out.println(" " + getString((short)table_scriptIDs[ss[i]]));1822}1823*/1824if (v.length == 1) {1825//the "allfonts" entries1826for (int i = 0; i < NUM_FONTS; i++) {1827table_sequences[k * NUM_FONTS + i] = v[0];1828}1829} else {1830for (int i = 0; i < NUM_FONTS; i++) {1831table_sequences[k * NUM_FONTS + i] = v[i];1832}1833}1834}1835//(4)1836head[INDEX_fontfileNameIDs] = (short)(head[INDEX_sequences] + table_sequences.length);1837table_fontfileNameIDs = toList(fontfileNameIDs);18381839//(5)1840head[INDEX_componentFontNameIDs] = (short)(head[INDEX_fontfileNameIDs] + table_fontfileNameIDs.length);1841table_componentFontNameIDs = toList(componentFontNameIDs);18421843//(6)componentFontNameID -> filenameID1844head[INDEX_filenames] = (short)(head[INDEX_componentFontNameIDs] + table_componentFontNameIDs.length);1845table_filenames = new short[table_componentFontNameIDs.length];1846Arrays.fill(table_filenames, (short) -1);18471848for (Entry<Short, Short> entry : filenames.entrySet()) {1849table_filenames[entry.getKey()] = entry.getValue();1850}18511852//(7)scriptID-> awtfontpath1853//the paths are stored as scriptID -> stringID in awtfontpahts1854head[INDEX_awtfontpaths] = (short)(head[INDEX_filenames] + table_filenames.length);1855table_awtfontpaths = new short[table_scriptIDs.length];1856for (Entry<Short, Short> entry : awtfontpaths.entrySet()) {1857table_awtfontpaths[entry.getKey()] = entry.getValue();1858}18591860//(8)exclusions1861head[INDEX_exclusions] = (short)(head[INDEX_awtfontpaths] + table_awtfontpaths.length);1862table_exclusions = new short[scriptIDs.size()];1863for (Entry<Short, int[]> entry : exclusions.entrySet()) {1864int[] exI = entry.getValue();1865char[] exC = new char[exI.length * 2];1866int j = 0;1867for (int i = 0; i < exI.length; i++) {1868exC[j++] = (char) (exI[i] >> 16);1869exC[j++] = (char) (exI[i] & 0xffff);1870}1871table_exclusions[entry.getKey()] = getStringID(new String (exC));1872}1873//(9)proportionals1874head[INDEX_proportionals] = (short)(head[INDEX_exclusions] + table_exclusions.length);1875table_proportionals = new short[proportionals.size() * 2];1876int j = 0;1877for (Entry<Short, Short> entry : proportionals.entrySet()) {1878table_proportionals[j++] = entry.getKey();1879table_proportionals[j++] = entry.getValue();1880}18811882//(10) see (1) for info, the only difference is "xxx.motif"1883head[INDEX_scriptFontsMotif] = (short)(head[INDEX_proportionals] + table_proportionals.length);1884if (scriptAllfontsMotif.size() != 0 || scriptFontsMotif.size() != 0) {1885len = table_scriptIDs.length + scriptFontsMotif.size() * 20;1886table_scriptFontsMotif = new short[len];18871888for (Entry<Short, Short> entry : scriptAllfontsMotif.entrySet()) {1889table_scriptFontsMotif[entry.getKey().intValue()] =1890(short)entry.getValue();1891}1892off = table_scriptIDs.length;1893for (Entry<Short, Short[]> entry : scriptFontsMotif.entrySet()) {1894table_scriptFontsMotif[entry.getKey().intValue()] = (short)-off;1895Short[] v = entry.getValue();1896int i = 0;1897while (i < 20) {1898if (v[i] != null) {1899table_scriptFontsMotif[off++] = v[i];1900} else {1901table_scriptFontsMotif[off++] = 0;1902}1903i++;1904}1905}1906} else {1907table_scriptFontsMotif = EMPTY_SHORT_ARRAY;1908}19091910//(11)short[] alphabeticSuffix1911head[INDEX_alphabeticSuffix] = (short)(head[INDEX_scriptFontsMotif] + table_scriptFontsMotif.length);1912table_alphabeticSuffix = new short[alphabeticSuffix.size() * 2];1913j = 0;1914for (Entry<Short, Short> entry : alphabeticSuffix.entrySet()) {1915table_alphabeticSuffix[j++] = entry.getKey();1916table_alphabeticSuffix[j++] = entry.getValue();1917}19181919//(15)short[] fallbackScriptIDs; just put the ID in head1920head[INDEX_fallbackScripts] = getShortArrayID(fallbackScriptIDs);19211922//(16)appendedfontpath1923head[INDEX_appendedfontpath] = getStringID(appendedfontpath);19241925//(17)version1926head[INDEX_version] = getStringID(version);19271928//(12)short[] StringIDs1929head[INDEX_stringIDs] = (short)(head[INDEX_alphabeticSuffix] + table_alphabeticSuffix.length);1930table_stringIDs = new short[stringIDNum + 1];1931System.arraycopy(stringIDs, 0, table_stringIDs, 0, stringIDNum + 1);19321933//(13)StringTable1934head[INDEX_stringTable] = (short)(head[INDEX_stringIDs] + stringIDNum + 1);1935table_stringTable = stringTable.toString().toCharArray();1936//(14)1937head[INDEX_TABLEEND] = (short)(head[INDEX_stringTable] + stringTable.length());19381939//StringTable cache1940stringCache = new String[table_stringIDs.length];1941}19421943//////////////////////////////////////////////1944private HashMap<String, Short> scriptIDs;1945//elc -> Encoding.Language.Country1946private HashMap<String, Short> elcIDs;1947//componentFontNameID starts from "1", "0" reserves for "undefined"1948private HashMap<String, Short> componentFontNameIDs;1949private HashMap<String, Short> fontfileNameIDs;1950private HashMap<String, Integer> logicalFontIDs;1951private HashMap<String, Integer> fontStyleIDs;19521953//componentFontNameID -> fontfileNameID1954private HashMap<Short, Short> filenames;19551956//elcID -> allfonts/logicalFont -> scriptID list1957//(1)if we have a "allfonts", then the length of the1958// value array is "1", otherwise it's 5, each font1959// must have their own individual entry.1960//scriptID list "short[]" is stored as an ID1961private HashMap<Short, short[]> sequences;19621963//scriptID ->logicFontID/fontStyleID->componentFontNameID,1964//a 20-entry array (5-name x 4-style) for each script1965private HashMap<Short, Short[]> scriptFonts;19661967//scriptID -> componentFontNameID1968private HashMap<Short, Short> scriptAllfonts;19691970//scriptID -> exclusionRanges[]1971private HashMap<Short, int[]> exclusions;19721973//scriptID -> fontpath1974private HashMap<Short, Short> awtfontpaths;19751976//fontID -> fontID1977private HashMap<Short, Short> proportionals;19781979//scriptID -> componentFontNameID1980private HashMap<Short, Short> scriptAllfontsMotif;19811982//scriptID ->logicFontID/fontStyleID->componentFontNameID,1983private HashMap<Short, Short[]> scriptFontsMotif;19841985//elcID -> stringID of alphabetic/XXXX1986private HashMap<Short, Short> alphabeticSuffix;19871988private short[] fallbackScriptIDs;1989private String version;1990private String appendedfontpath;19911992private void initLogicalNameStyle() {1993logicalFontIDs = new HashMap<String, Integer>();1994fontStyleIDs = new HashMap<String, Integer>();1995logicalFontIDs.put("serif", 0);1996logicalFontIDs.put("sansserif", 1);1997logicalFontIDs.put("monospaced", 2);1998logicalFontIDs.put("dialog", 3);1999logicalFontIDs.put("dialoginput",4);2000fontStyleIDs.put("plain", 0);2001fontStyleIDs.put("bold", 1);2002fontStyleIDs.put("italic", 2);2003fontStyleIDs.put("bolditalic", 3);2004}20052006private void initHashMaps() {2007scriptIDs = new HashMap<String, Short>();2008elcIDs = new HashMap<String, Short>();2009componentFontNameIDs = new HashMap<String, Short>();2010/*Init these tables to allow componentFontNameID, fontfileNameIDs2011to start from "1".2012*/2013componentFontNameIDs.put("", Short.valueOf((short)0));20142015fontfileNameIDs = new HashMap<String, Short>();2016filenames = new HashMap<Short, Short>();2017sequences = new HashMap<Short, short[]>();2018scriptFonts = new HashMap<Short, Short[]>();2019scriptAllfonts = new HashMap<Short, Short>();2020exclusions = new HashMap<Short, int[]>();2021awtfontpaths = new HashMap<Short, Short>();2022proportionals = new HashMap<Short, Short>();2023scriptFontsMotif = new HashMap<Short, Short[]>();2024scriptAllfontsMotif = new HashMap<Short, Short>();2025alphabeticSuffix = new HashMap<Short, Short>();2026fallbackScriptIDs = EMPTY_SHORT_ARRAY;2027/*2028version2029appendedfontpath2030*/2031}20322033private int[] parseExclusions(String key, String exclusions) {2034if (exclusions == null) {2035return EMPTY_INT_ARRAY;2036}2037// range format is xxxx-XXXX,yyyyyy-YYYYYY,.....2038int numExclusions = 1;2039int pos = 0;2040while ((pos = exclusions.indexOf(',', pos)) != -1) {2041numExclusions++;2042pos++;2043}2044int[] exclusionRanges = new int[numExclusions * 2];2045pos = 0;2046int newPos = 0;2047for (int j = 0; j < numExclusions * 2; ) {2048String lower, upper;2049int lo = 0, up = 0;2050try {2051newPos = exclusions.indexOf('-', pos);2052lower = exclusions.substring(pos, newPos);2053pos = newPos + 1;2054newPos = exclusions.indexOf(',', pos);2055if (newPos == -1) {2056newPos = exclusions.length();2057}2058upper = exclusions.substring(pos, newPos);2059pos = newPos + 1;2060int lowerLength = lower.length();2061int upperLength = upper.length();2062if (lowerLength != 4 && lowerLength != 62063|| upperLength != 4 && upperLength != 6) {2064throw new Exception();2065}2066lo = Integer.parseInt(lower, 16);2067up = Integer.parseInt(upper, 16);2068if (lo > up) {2069throw new Exception();2070}2071} catch (Exception e) {2072if (FontUtilities.debugFonts() &&2073logger != null) {2074logger.config("Failed parsing " + key +2075" property of font configuration.");20762077}2078return EMPTY_INT_ARRAY;2079}2080exclusionRanges[j++] = lo;2081exclusionRanges[j++] = up;2082}2083return exclusionRanges;2084}20852086private Short getID(HashMap<String, Short> map, String key) {2087Short ret = map.get(key);2088if ( ret == null) {2089map.put(key, (short)map.size());2090return map.get(key);2091}2092return ret;2093}20942095@SuppressWarnings("serial") // JDK-implementation class2096class FontProperties extends Properties {2097public synchronized Object put(Object k, Object v) {2098parseProperty((String)k, (String)v);2099return null;2100}2101}21022103private void parseProperty(String key, String value) {2104if (key.startsWith("filename.")) {2105//the only special case is "MingLiu_HKSCS" which has "_" in its2106//facename, we don't want to replace the "_" with " "2107key = key.substring(9);2108if (!"MingLiU_HKSCS".equals(key)) {2109key = key.replace('_', ' ');2110}2111Short faceID = getID(componentFontNameIDs, key);2112Short fileID = getID(fontfileNameIDs, value);2113//System.out.println("faceID=" + faceID + "/" + key + " -> "2114// + "fileID=" + fileID + "/" + value);2115filenames.put(faceID, fileID);2116} else if (key.startsWith("exclusion.")) {2117key = key.substring(10);2118exclusions.put(getID(scriptIDs,key), parseExclusions(key,value));2119} else if (key.startsWith("sequence.")) {2120key = key.substring(9);2121boolean hasDefault = false;2122boolean has1252 = false;21232124//get the scriptID list2125String[] ss = splitSequence(value).toArray(EMPTY_STRING_ARRAY);2126short [] sa = new short[ss.length];2127for (int i = 0; i < ss.length; i++) {2128if ("alphabetic/default".equals(ss[i])) {2129//System.out.println(key + " -> " + ss[i]);2130ss[i] = "alphabetic";2131hasDefault = true;2132} else if ("alphabetic/1252".equals(ss[i])) {2133//System.out.println(key + " -> " + ss[i]);2134ss[i] = "alphabetic";2135has1252 = true;2136}2137sa[i] = getID(scriptIDs, ss[i]).shortValue();2138//System.out.println("scriptID=" + si[i] + "/" + ss[i]);2139}2140//convert the "short[] -> string -> stringID"2141short scriptArrayID = getShortArrayID(sa);2142Short elcID = null;2143int dot = key.indexOf('.');2144if (dot == -1) {2145if ("fallback".equals(key)) {2146fallbackScriptIDs = sa;2147return;2148}2149if ("allfonts".equals(key)) {2150elcID = getID(elcIDs, "NULL.NULL.NULL");2151} else {2152if (logger != null) {2153logger.config("Error sequence def: <sequence." + key + ">");2154}2155return;2156}2157} else {2158elcID = getID(elcIDs, key.substring(dot + 1));2159//System.out.println("elcID=" + elcID + "/" + key.substring(dot + 1));2160key = key.substring(0, dot);2161}2162short[] scriptArrayIDs = null;2163if ("allfonts".equals(key)) {2164scriptArrayIDs = new short[1];2165scriptArrayIDs[0] = scriptArrayID;2166} else {2167scriptArrayIDs = sequences.get(elcID);2168if (scriptArrayIDs == null) {2169scriptArrayIDs = new short[5];2170}2171Integer fid = logicalFontIDs.get(key);2172if (fid == null) {2173if (logger != null) {2174logger.config("Unrecognizable logicfont name " + key);2175}2176return;2177}2178//System.out.println("sequence." + key + "/" + id);2179scriptArrayIDs[fid.intValue()] = scriptArrayID;2180}2181sequences.put(elcID, scriptArrayIDs);2182if (hasDefault) {2183alphabeticSuffix.put(elcID, getStringID("default"));2184} else2185if (has1252) {2186alphabeticSuffix.put(elcID, getStringID("1252"));2187}2188} else if (key.startsWith("allfonts.")) {2189key = key.substring(9);2190if (key.endsWith(".motif")) {2191key = key.substring(0, key.length() - 6);2192//System.out.println("motif: all." + key + "=" + value);2193scriptAllfontsMotif.put(getID(scriptIDs,key), getID(componentFontNameIDs,value));2194} else {2195scriptAllfonts.put(getID(scriptIDs,key), getID(componentFontNameIDs,value));2196}2197} else if (key.startsWith("awtfontpath.")) {2198key = key.substring(12);2199//System.out.println("scriptID=" + getID(scriptIDs, key) + "/" + key);2200awtfontpaths.put(getID(scriptIDs, key), getStringID(value));2201} else if ("version".equals(key)) {2202version = value;2203} else if ("appendedfontpath".equals(key)) {2204appendedfontpath = value;2205} else if (key.startsWith("proportional.")) {2206key = key.substring(13).replace('_', ' ');2207//System.out.println(key + "=" + value);2208proportionals.put(getID(componentFontNameIDs, key),2209getID(componentFontNameIDs, value));2210} else {2211//"name.style.script(.motif)", we don't care anything else2212int dot1, dot2;2213boolean isMotif = false;22142215dot1 = key.indexOf('.');2216if (dot1 == -1) {2217if (logger != null) {2218logger.config("Failed parsing " + key +2219" property of font configuration.");22202221}2222return;2223}2224dot2 = key.indexOf('.', dot1 + 1);2225if (dot2 == -1) {2226if (logger != null) {2227logger.config("Failed parsing " + key +2228" property of font configuration.");22292230}2231return;2232}2233if (key.endsWith(".motif")) {2234key = key.substring(0, key.length() - 6);2235isMotif = true;2236//System.out.println("motif: " + key + "=" + value);2237}2238Integer nameID = logicalFontIDs.get(key.substring(0, dot1));2239Integer styleID = fontStyleIDs.get(key.substring(dot1+1, dot2));2240Short scriptID = getID(scriptIDs, key.substring(dot2 + 1));2241if (nameID == null || styleID == null) {2242if (logger != null) {2243logger.config("unrecognizable logicfont name/style at " + key);2244}2245return;2246}2247Short[] pnids;2248if (isMotif) {2249pnids = scriptFontsMotif.get(scriptID);2250} else {2251pnids = scriptFonts.get(scriptID);2252}2253if (pnids == null) {2254pnids = new Short[20];2255}2256pnids[nameID.intValue() * NUM_STYLES + styleID.intValue()]2257= getID(componentFontNameIDs, value);2258/*2259System.out.println("key=" + key + "/<" + nameID + "><" + styleID2260+ "><" + scriptID + ">=" + value2261+ "/" + getID(componentFontNameIDs, value));2262*/2263if (isMotif) {2264scriptFontsMotif.put(scriptID, pnids);2265} else {2266scriptFonts.put(scriptID, pnids);2267}2268}2269}2270}2271}227222732274