Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/share/classes/sun/awt/FontConfiguration.java
38827 views
/*1* Copyright (c) 1996, 2014, 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 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.getLogger()86.info("Creating standard Font Configuration");87}88if (FontUtilities.debugFonts() && logger == null) {89logger = PlatformLogger.getLogger("sun.awt.FontConfiguration");90}91fontManager = fm;92setOsNameAndVersion(); /* static initialization */93setEncoding(); /* static initialization */94/* Separating out the file location from the rest of the95* initialisation, so the caller has the option of doing96* something else if a suitable file isn't found.97*/98findFontConfigFile();99}100101public synchronized boolean init() {102if (!inited) {103this.preferLocaleFonts = false;104this.preferPropFonts = false;105setFontConfiguration();106readFontConfigFile(fontConfigFile);107initFontConfig();108inited = true;109}110return true;111}112113public FontConfiguration(SunFontManager fm,114boolean preferLocaleFonts,115boolean preferPropFonts) {116fontManager = fm;117if (FontUtilities.debugFonts()) {118FontUtilities.getLogger()119.info("Creating alternate Font Configuration");120}121this.preferLocaleFonts = preferLocaleFonts;122this.preferPropFonts = preferPropFonts;123/* fontConfig should be initialised by default constructor, and124* its data tables can be shared, since readFontConfigFile doesn't125* update any other state. Also avoid a doPrivileged block.126*/127initFontConfig();128}129130/**131* Fills in this instance's osVersion and osName members. By132* default uses the system properties os.name and os.version;133* subclasses may override.134*/135protected void setOsNameAndVersion() {136osName = System.getProperty("os.name");137osVersion = System.getProperty("os.version");138}139140private void setEncoding() {141encoding = Charset.defaultCharset().name();142startupLocale = SunToolkit.getStartupLocale();143}144145/////////////////////////////////////////////////////////////////////146// methods for loading the FontConfig file //147/////////////////////////////////////////////////////////////////////148149public boolean foundOsSpecificFile() {150return foundOsSpecificFile;151}152153/* Smoke test to see if we can trust this configuration by testing if154* the first slot of a composite font maps to an installed file.155*/156public boolean fontFilesArePresent() {157init();158short fontNameID = compFontNameIDs[0][0][0];159short fileNameID = getComponentFileID(fontNameID);160final String fileName = mapFileName(getComponentFileName(fileNameID));161Boolean exists = (Boolean)java.security.AccessController.doPrivileged(162new java.security.PrivilegedAction() {163public Object run() {164try {165File f = new File(fileName);166return Boolean.valueOf(f.exists());167}168catch (Exception e) {169return false;170}171}172});173return exists.booleanValue();174}175176private void findFontConfigFile() {177178foundOsSpecificFile = true; // default assumption.179String javaHome = System.getProperty("java.home");180if (javaHome == null) {181throw new Error("java.home property not set");182}183javaLib = javaHome + File.separator + "lib";184String userConfigFile = System.getProperty("sun.awt.fontconfig");185if (userConfigFile != null) {186fontConfigFile = new File(userConfigFile);187} else {188fontConfigFile = findFontConfigFile(javaLib);189}190}191192private void readFontConfigFile(File f) {193/* This is invoked here as readFontConfigFile is only invoked194* once per VM, and always in a privileged context, thus the195* directory containing installed fall back fonts is accessed196* from this context197*/198getInstalledFallbackFonts(javaLib);199200if (f != null) {201try {202FileInputStream in = new FileInputStream(f.getPath());203if (isProperties) {204loadProperties(in);205} else {206loadBinary(in);207}208in.close();209if (FontUtilities.debugFonts()) {210logger.config("Read logical font configuration from " + f);211}212} catch (IOException e) {213if (FontUtilities.debugFonts()) {214logger.config("Failed to read logical font configuration from " + f);215}216}217}218String version = getVersion();219if (!"1".equals(version) && FontUtilities.debugFonts()) {220logger.config("Unsupported fontconfig version: " + version);221}222}223224protected void getInstalledFallbackFonts(String javaLib) {225String fallbackDirName = javaLib + File.separator +226"fonts" + File.separator + "fallback";227228File fallbackDir = new File(fallbackDirName);229if (fallbackDir.exists() && fallbackDir.isDirectory()) {230String[] ttfs = fallbackDir.list(fontManager.getTrueTypeFilter());231String[] t1s = fallbackDir.list(fontManager.getType1Filter());232int numTTFs = (ttfs == null) ? 0 : ttfs.length;233int numT1s = (t1s == null) ? 0 : t1s.length;234int len = numTTFs + numT1s;235if (numTTFs + numT1s == 0) {236return;237}238installedFallbackFontFiles = new String[len];239for (int i=0; i<numTTFs; i++) {240installedFallbackFontFiles[i] =241fallbackDir + File.separator + ttfs[i];242}243for (int i=0; i<numT1s; i++) {244installedFallbackFontFiles[i+numTTFs] =245fallbackDir + File.separator + t1s[i];246}247fontManager.registerFontsInDir(fallbackDirName);248}249}250251private File findImpl(String fname) {252File f = new File(fname + ".properties");253if (f.canRead()) {254isProperties = true;255return f;256}257f = new File(fname + ".bfc");258if (f.canRead()) {259isProperties = false;260return f;261}262return null;263}264265private File findFontConfigFile(String javaLib) {266String baseName = javaLib + File.separator + "fontconfig";267File configFile;268String osMajorVersion = null;269if (osVersion != null && osName != null) {270configFile = findImpl(baseName + "." + osName + "." + osVersion);271if (configFile != null) {272return configFile;273}274int decimalPointIndex = osVersion.indexOf(".");275if (decimalPointIndex != -1) {276osMajorVersion = osVersion.substring(0, osVersion.indexOf("."));277configFile = findImpl(baseName + "." + osName + "." + osMajorVersion);278if (configFile != null) {279return configFile;280}281}282}283if (osName != null) {284configFile = findImpl(baseName + "." + osName);285if (configFile != null) {286return configFile;287}288}289if (osVersion != null) {290configFile = findImpl(baseName + "." + osVersion);291if (configFile != null) {292return configFile;293}294if (osMajorVersion != null) {295configFile = findImpl(baseName + "." + osMajorVersion);296if (configFile != null) {297return configFile;298}299}300}301foundOsSpecificFile = false;302303configFile = findImpl(baseName);304if (configFile != null) {305return configFile;306}307return null;308}309310/* Initialize the internal data tables from binary format font311* configuration file.312*/313public static void loadBinary(InputStream inStream) throws IOException {314DataInputStream in = new DataInputStream(inStream);315head = readShortTable(in, HEAD_LENGTH);316int[] tableSizes = new int[INDEX_TABLEEND];317for (int i = 0; i < INDEX_TABLEEND; i++) {318tableSizes[i] = head[i + 1] - head[i];319}320table_scriptIDs = readShortTable(in, tableSizes[INDEX_scriptIDs]);321table_scriptFonts = readShortTable(in, tableSizes[INDEX_scriptFonts]);322table_elcIDs = readShortTable(in, tableSizes[INDEX_elcIDs]);323table_sequences = readShortTable(in, tableSizes[INDEX_sequences]);324table_fontfileNameIDs = readShortTable(in, tableSizes[INDEX_fontfileNameIDs]);325table_componentFontNameIDs = readShortTable(in, tableSizes[INDEX_componentFontNameIDs]);326table_filenames = readShortTable(in, tableSizes[INDEX_filenames]);327table_awtfontpaths = readShortTable(in, tableSizes[INDEX_awtfontpaths]);328table_exclusions = readShortTable(in, tableSizes[INDEX_exclusions]);329table_proportionals = readShortTable(in, tableSizes[INDEX_proportionals]);330table_scriptFontsMotif = readShortTable(in, tableSizes[INDEX_scriptFontsMotif]);331table_alphabeticSuffix = readShortTable(in, tableSizes[INDEX_alphabeticSuffix]);332table_stringIDs = readShortTable(in, tableSizes[INDEX_stringIDs]);333334//StringTable cache335stringCache = new String[table_stringIDs.length + 1];336337int len = tableSizes[INDEX_stringTable];338byte[] bb = new byte[len * 2];339table_stringTable = new char[len];340in.read(bb);341int i = 0, j = 0;342while (i < len) {343table_stringTable[i++] = (char)(bb[j++] << 8 | (bb[j++] & 0xff));344}345if (verbose) {346dump();347}348}349350/* Generate a binary format font configuration from internal data351* tables.352*/353public static void saveBinary(OutputStream out) throws IOException {354sanityCheck();355356DataOutputStream dataOut = new DataOutputStream(out);357writeShortTable(dataOut, head);358writeShortTable(dataOut, table_scriptIDs);359writeShortTable(dataOut, table_scriptFonts);360writeShortTable(dataOut, table_elcIDs);361writeShortTable(dataOut, table_sequences);362writeShortTable(dataOut, table_fontfileNameIDs);363writeShortTable(dataOut, table_componentFontNameIDs);364writeShortTable(dataOut, table_filenames);365writeShortTable(dataOut, table_awtfontpaths);366writeShortTable(dataOut, table_exclusions);367writeShortTable(dataOut, table_proportionals);368writeShortTable(dataOut, table_scriptFontsMotif);369writeShortTable(dataOut, table_alphabeticSuffix);370writeShortTable(dataOut, table_stringIDs);371//stringTable372dataOut.writeChars(new String(table_stringTable));373out.close();374if (verbose) {375dump();376}377}378379//private static boolean loadingProperties;380private static short stringIDNum;381private static short[] stringIDs;382private static StringBuilder stringTable;383384public static void loadProperties(InputStream in) throws IOException {385//loadingProperties = true;386//StringID starts from "1", "0" is reserved for "not defined"387stringIDNum = 1;388stringIDs = new short[1000];389stringTable = new StringBuilder(4096);390391if (verbose && logger == null) {392logger = PlatformLogger.getLogger("sun.awt.FontConfiguration");393}394new PropertiesHandler().load(in);395396//loadingProperties = false;397stringIDs = null;398stringTable = null;399}400401402/////////////////////////////////////////////////////////////////////403// methods for initializing the FontConfig //404/////////////////////////////////////////////////////////////////////405406/**407* set initLocale, initEncoding and initELC for this FontConfig object408* currently we just simply use the startup locale and encoding409*/410private void initFontConfig() {411initLocale = startupLocale;412initEncoding = encoding;413if (preferLocaleFonts && !willReorderForStartupLocale()) {414preferLocaleFonts = false;415}416initELC = getInitELC();417initAllComponentFonts();418}419420//"ELC" stands for "Encoding.Language.Country". This method returns421//the ID of the matched elc setting of "initLocale" in elcIDs table.422//If no match is found, it returns the default ID, which is423//"NULL.NULL.NULL" in elcIDs table.424private short getInitELC() {425if (initELC != -1) {426return initELC;427}428HashMap <String, Integer> elcIDs = new HashMap<String, Integer>();429for (int i = 0; i < table_elcIDs.length; i++) {430elcIDs.put(getString(table_elcIDs[i]), i);431}432String language = initLocale.getLanguage();433String country = initLocale.getCountry();434String elc;435if (elcIDs.containsKey(elc=initEncoding + "." + language + "." + country)436|| elcIDs.containsKey(elc=initEncoding + "." + language)437|| elcIDs.containsKey(elc=initEncoding)) {438initELC = elcIDs.get(elc).shortValue();439} else {440initELC = elcIDs.get("NULL.NULL.NULL").shortValue();441}442int i = 0;443while (i < table_alphabeticSuffix.length) {444if (initELC == table_alphabeticSuffix[i]) {445alphabeticSuffix = getString(table_alphabeticSuffix[i + 1]);446return initELC;447}448i += 2;449}450return initELC;451}452453public static boolean verbose;454private short initELC = -1;455private Locale initLocale;456private String initEncoding;457private String alphabeticSuffix;458459private short[][][] compFontNameIDs = new short[NUM_FONTS][NUM_STYLES][];460private int[][][] compExclusions = new int[NUM_FONTS][][];461private int[] compCoreNum = new int[NUM_FONTS];462463private Set<Short> coreFontNameIDs = new HashSet<Short>();464private Set<Short> fallbackFontNameIDs = new HashSet<Short>();465466private void initAllComponentFonts() {467short[] fallbackScripts = getFallbackScripts();468for (int fontIndex = 0; fontIndex < NUM_FONTS; fontIndex++) {469short[] coreScripts = getCoreScripts(fontIndex);470compCoreNum[fontIndex] = coreScripts.length;471/*472System.out.println("coreScriptID=" + table_sequences[initELC * 5 + fontIndex]);473for (int i = 0; i < coreScripts.length; i++) {474System.out.println(" " + i + " :" + getString(table_scriptIDs[coreScripts[i]]));475}476*/477//init exclusionRanges478int[][] exclusions = new int[coreScripts.length][];479for (int i = 0; i < coreScripts.length; i++) {480exclusions[i] = getExclusionRanges(coreScripts[i]);481}482compExclusions[fontIndex] = exclusions;483//init componentFontNames484for (int styleIndex = 0; styleIndex < NUM_STYLES; styleIndex++) {485int index;486short[] nameIDs = new short[coreScripts.length + fallbackScripts.length];487//core488for (index = 0; index < coreScripts.length; index++) {489nameIDs[index] = getComponentFontID(coreScripts[index],490fontIndex, styleIndex);491if (preferLocaleFonts && localeMap != null &&492fontManager.usingAlternateFontforJALocales()) {493nameIDs[index] = remapLocaleMap(fontIndex, styleIndex,494coreScripts[index], nameIDs[index]);495}496if (preferPropFonts) {497nameIDs[index] = remapProportional(fontIndex, nameIDs[index]);498}499//System.out.println("nameid=" + nameIDs[index]);500coreFontNameIDs.add(nameIDs[index]);501}502//fallback503for (int i = 0; i < fallbackScripts.length; i++) {504short id = getComponentFontID(fallbackScripts[i],505fontIndex, styleIndex);506if (preferLocaleFonts && localeMap != null &&507fontManager.usingAlternateFontforJALocales()) {508id = remapLocaleMap(fontIndex, styleIndex, fallbackScripts[i], id);509}510if (preferPropFonts) {511id = remapProportional(fontIndex, id);512}513if (contains(nameIDs, id, index)) {514continue;515}516/*517System.out.println("fontIndex=" + fontIndex + ", styleIndex=" + styleIndex518+ ", fbIndex=" + i + ",fbS=" + fallbackScripts[i] + ", id=" + id);519*/520fallbackFontNameIDs.add(id);521nameIDs[index++] = id;522}523if (index < nameIDs.length) {524short[] newNameIDs = new short[index];525System.arraycopy(nameIDs, 0, newNameIDs, 0, index);526nameIDs = newNameIDs;527}528compFontNameIDs[fontIndex][styleIndex] = nameIDs;529}530}531}532533private short remapLocaleMap(int fontIndex, int styleIndex, short scriptID, short fontID) {534String scriptName = getString(table_scriptIDs[scriptID]);535536String value = (String)localeMap.get(scriptName);537if (value == null) {538String fontName = fontNames[fontIndex];539String styleName = styleNames[styleIndex];540value = (String)localeMap.get(fontName + "." + styleName + "." + scriptName);541}542if (value == null) {543return fontID;544}545546for (int i = 0; i < table_componentFontNameIDs.length; i++) {547String name = getString(table_componentFontNameIDs[i]);548if (value.equalsIgnoreCase(name)) {549fontID = (short)i;550break;551}552}553return fontID;554}555556public static boolean hasMonoToPropMap() {557return table_proportionals != null && table_proportionals.length != 0;558}559560private short remapProportional(int fontIndex, short id) {561if (preferPropFonts &&562table_proportionals.length != 0 &&563fontIndex != 2 && //"monospaced"564fontIndex != 4) { //"dialoginput"565int i = 0;566while (i < table_proportionals.length) {567if (table_proportionals[i] == id) {568return table_proportionals[i + 1];569}570i += 2;571}572}573return id;574}575576/////////////////////////////////////////////////////////////////////577// Methods for handling font and style names //578/////////////////////////////////////////////////////////////////////579protected static final int NUM_FONTS = 5;580protected static final int NUM_STYLES = 4;581protected static final String[] fontNames582= {"serif", "sansserif", "monospaced", "dialog", "dialoginput"};583protected static final String[] publicFontNames584= {Font.SERIF, Font.SANS_SERIF, Font.MONOSPACED, Font.DIALOG,585Font.DIALOG_INPUT};586protected static final String[] styleNames587= {"plain", "bold", "italic", "bolditalic"};588589/**590* Checks whether the given font family name is a valid logical font name.591* The check is case insensitive.592*/593public static boolean isLogicalFontFamilyName(String fontName) {594return isLogicalFontFamilyNameLC(fontName.toLowerCase(Locale.ENGLISH));595}596597/**598* Checks whether the given font family name is a valid logical font name.599* The check is case sensitive.600*/601public static boolean isLogicalFontFamilyNameLC(String fontName) {602for (int i = 0; i < fontNames.length; i++) {603if (fontName.equals(fontNames[i])) {604return true;605}606}607return false;608}609610/**611* Checks whether the given style name is a valid logical font style name.612*/613private static boolean isLogicalFontStyleName(String styleName) {614for (int i = 0; i < styleNames.length; i++) {615if (styleName.equals(styleNames[i])) {616return true;617}618}619return false;620}621622/**623* Checks whether the given font face name is a valid logical font name.624* The check is case insensitive.625*/626public static boolean isLogicalFontFaceName(String fontName) {627return isLogicalFontFaceNameLC(fontName.toLowerCase(Locale.ENGLISH));628}629630/**631* Checks whether the given font face name is a valid logical font name.632* The check is case sensitive.633*/634public static boolean isLogicalFontFaceNameLC(String fontName) {635int period = fontName.indexOf('.');636if (period >= 0) {637String familyName = fontName.substring(0, period);638String styleName = fontName.substring(period + 1);639return isLogicalFontFamilyName(familyName) &&640isLogicalFontStyleName(styleName);641} else {642return isLogicalFontFamilyName(fontName);643}644}645646protected static int getFontIndex(String fontName) {647return getArrayIndex(fontNames, fontName);648}649650protected static int getStyleIndex(String styleName) {651return getArrayIndex(styleNames, styleName);652}653654private static int getArrayIndex(String[] names, String name) {655for (int i = 0; i < names.length; i++) {656if (name.equals(names[i])) {657return i;658}659}660assert false;661return 0;662}663664protected static int getStyleIndex(int style) {665switch (style) {666case Font.PLAIN:667return 0;668case Font.BOLD:669return 1;670case Font.ITALIC:671return 2;672case Font.BOLD | Font.ITALIC:673return 3;674default:675return 0;676}677}678679protected static String getFontName(int fontIndex) {680return fontNames[fontIndex];681}682683protected static String getStyleName(int styleIndex) {684return styleNames[styleIndex];685}686687/**688* Returns the font face name for the given logical font689* family name and style.690* The style argument is interpreted as in java.awt.Font.Font.691*/692public static String getLogicalFontFaceName(String familyName, int style) {693assert isLogicalFontFamilyName(familyName);694return familyName.toLowerCase(Locale.ENGLISH) + "." + getStyleString(style);695}696697/**698* Returns the string typically used in properties files699* for the given style.700* The style argument is interpreted as in java.awt.Font.Font.701*/702public static String getStyleString(int style) {703return getStyleName(getStyleIndex(style));704}705706/**707* Returns a fallback name for the given font name. For a few known708* font names, matching logical font names are returned. For all709* other font names, defaultFallback is returned.710* defaultFallback differs between AWT and 2D.711*/712public abstract String getFallbackFamilyName(String fontName, String defaultFallback);713714/**715* Returns the 1.1 equivalent for some old 1.0 font family names for716* which we need to maintain compatibility in some configurations.717* Returns null for other font names.718*/719protected String getCompatibilityFamilyName(String fontName) {720fontName = fontName.toLowerCase(Locale.ENGLISH);721if (fontName.equals("timesroman")) {722return "serif";723} else if (fontName.equals("helvetica")) {724return "sansserif";725} else if (fontName.equals("courier")) {726return "monospaced";727}728return null;729}730731protected static String[] installedFallbackFontFiles = null;732733/**734* Maps a file name given in the font configuration file735* to a format appropriate for the platform.736*/737protected String mapFileName(String fileName) {738return fileName;739}740741//////////////////////////////////////////////////////////////////////742// reordering //743//////////////////////////////////////////////////////////////////////744745/* Mappings from file encoding to font config name for font supporting746* the corresponding language. This is filled in by initReorderMap()747*/748protected HashMap reorderMap = null;749750/* Platform-specific mappings */751protected abstract void initReorderMap();752753/* Move item at index "src" to "dst", shuffling all values in754* between down755*/756private void shuffle(String[] seq, int src, int dst) {757if (dst >= src) {758return;759}760String tmp = seq[src];761for (int i=src; i>dst; i--) {762seq[i] = seq[i-1];763}764seq[dst] = tmp;765}766767/* Called to determine if there's a re-order sequence for this locale/768* encoding. If there's none then the caller can "bail" and avoid769* unnecessary work770*/771public static boolean willReorderForStartupLocale() {772return getReorderSequence() != null;773}774775private static Object getReorderSequence() {776if (fontConfig.reorderMap == null) {777fontConfig.initReorderMap();778}779HashMap reorderMap = fontConfig.reorderMap;780781/* Find the most specific mapping */782String language = startupLocale.getLanguage();783String country = startupLocale.getCountry();784Object val = reorderMap.get(encoding + "." + language + "." + country);785if (val == null) {786val = reorderMap.get(encoding + "." + language);787}788if (val == null) {789val = reorderMap.get(encoding);790}791return val;792}793794/* This method reorders the sequence such that the matches for the795* file encoding are moved ahead of other elements.796* If an encoding uses more than one font, they are all moved up.797*/798private void reorderSequenceForLocale(String[] seq) {799Object val = getReorderSequence();800if (val instanceof String) {801for (int i=0; i< seq.length; i++) {802if (seq[i].equals(val)) {803shuffle(seq, i, 0);804return;805}806}807} else if (val instanceof String[]) {808String[] fontLangs = (String[])val;809for (int l=0; l<fontLangs.length;l++) {810for (int i=0; i<seq.length;i++) {811if (seq[i].equals(fontLangs[l])) {812shuffle(seq, i, l);813}814}815}816}817}818819private static Vector splitSequence(String sequence) {820//String.split would be more convenient, but incurs big performance penalty821Vector parts = new Vector();822int start = 0;823int end;824while ((end = sequence.indexOf(',', start)) >= 0) {825parts.add(sequence.substring(start, end));826start = end + 1;827}828if (sequence.length() > start) {829parts.add(sequence.substring(start, sequence.length()));830}831return parts;832}833834protected String[] split(String sequence) {835Vector v = splitSequence(sequence);836return (String[])v.toArray(new String[0]);837}838839////////////////////////////////////////////////////////////////////////840// Methods for extracting information from the fontconfig data for AWT//841////////////////////////////////////////////////////////////////////////842private Hashtable charsetRegistry = new Hashtable(5);843844/**845* Returns FontDescriptors describing the physical fonts used for the846* given logical font name and style. The font name is interpreted847* in a case insensitive way.848* The style argument is interpreted as in java.awt.Font.Font.849*/850public FontDescriptor[] getFontDescriptors(String fontName, int style) {851assert isLogicalFontFamilyName(fontName);852fontName = fontName.toLowerCase(Locale.ENGLISH);853int fontIndex = getFontIndex(fontName);854int styleIndex = getStyleIndex(style);855return getFontDescriptors(fontIndex, styleIndex);856}857private FontDescriptor[][][] fontDescriptors =858new FontDescriptor[NUM_FONTS][NUM_STYLES][];859860private FontDescriptor[] getFontDescriptors(int fontIndex, int styleIndex) {861FontDescriptor[] descriptors = fontDescriptors[fontIndex][styleIndex];862if (descriptors == null) {863descriptors = buildFontDescriptors(fontIndex, styleIndex);864fontDescriptors[fontIndex][styleIndex] = descriptors;865}866return descriptors;867}868869protected FontDescriptor[] buildFontDescriptors(int fontIndex, int styleIndex) {870String fontName = fontNames[fontIndex];871String styleName = styleNames[styleIndex];872873short[] scriptIDs = getCoreScripts(fontIndex);874short[] nameIDs = compFontNameIDs[fontIndex][styleIndex];875String[] sequence = new String[scriptIDs.length];876String[] names = new String[scriptIDs.length];877for (int i = 0; i < sequence.length; i++) {878names[i] = getComponentFontName(nameIDs[i]);879sequence[i] = getScriptName(scriptIDs[i]);880if (alphabeticSuffix != null && "alphabetic".equals(sequence[i])) {881sequence[i] = sequence[i] + "/" + alphabeticSuffix;882}883}884int[][] fontExclusionRanges = compExclusions[fontIndex];885886FontDescriptor[] descriptors = new FontDescriptor[names.length];887888for (int i = 0; i < names.length; i++) {889String awtFontName;890String encoding;891892awtFontName = makeAWTFontName(names[i], sequence[i]);893894// look up character encoding895encoding = getEncoding(names[i], sequence[i]);896if (encoding == null) {897encoding = "default";898}899CharsetEncoder enc900= getFontCharsetEncoder(encoding.trim(), awtFontName);901902// we already have the exclusion ranges903int[] exclusionRanges = fontExclusionRanges[i];904905// create descriptor906descriptors[i] = new FontDescriptor(awtFontName, enc, exclusionRanges);907}908return descriptors;909}910911/**912* Returns the AWT font name for the given platform font name and913* character subset.914*/915protected String makeAWTFontName(String platformFontName,916String characterSubsetName) {917return platformFontName;918}919920/**921* Returns the java.io name of the platform character encoding for the922* given AWT font name and character subset. May return "default"923* to indicate that getDefaultFontCharset should be called to obtain924* a charset encoder.925*/926protected abstract String getEncoding(String awtFontName,927String characterSubsetName);928929private CharsetEncoder getFontCharsetEncoder(final String charsetName,930String fontName) {931932Charset fc = null;933if (charsetName.equals("default")) {934fc = (Charset) charsetRegistry.get(fontName);935} else {936fc = (Charset) charsetRegistry.get(charsetName);937}938if (fc != null) {939return fc.newEncoder();940}941942if (!charsetName.startsWith("sun.awt.") && !charsetName.equals("default")) {943fc = Charset.forName(charsetName);944} else {945Class fcc = (Class) AccessController.doPrivileged(new PrivilegedAction() {946public Object run() {947try {948return Class.forName(charsetName, true,949ClassLoader.getSystemClassLoader());950} catch (ClassNotFoundException e) {951}952return null;953}954});955956if (fcc != null) {957try {958fc = (Charset) fcc.newInstance();959} catch (Exception e) {960}961}962}963if (fc == null) {964fc = getDefaultFontCharset(fontName);965}966967if (charsetName.equals("default")){968charsetRegistry.put(fontName, fc);969} else {970charsetRegistry.put(charsetName, fc);971}972return fc.newEncoder();973}974975protected abstract Charset getDefaultFontCharset(976String fontName);977978/* This retrieves the platform font directories (path) calculated979* by setAWTFontPathSequence(String[]). The default implementation980* returns null, its expected that X11 platforms may return981* non-null.982*/983public HashSet<String> getAWTFontPathSet() {984return null;985}986987////////////////////////////////////////////////////////////////////////988// methods for extracting information from the fontconfig data for 2D //989////////////////////////////////////////////////////////////////////////990991/**992* Returns an array of composite font descriptors for all logical font993* faces.994* If the font configuration file doesn't specify Lucida Sans Regular995* or the given fallback font as component fonts, they are added here.996*/997public CompositeFontDescriptor[] get2DCompositeFontInfo() {998CompositeFontDescriptor[] result =999new CompositeFontDescriptor[NUM_FONTS * NUM_STYLES];1000String defaultFontFile = fontManager.getDefaultFontFile();1001String defaultFontFaceName = fontManager.getDefaultFontFaceName();10021003for (int fontIndex = 0; fontIndex < NUM_FONTS; fontIndex++) {1004String fontName = publicFontNames[fontIndex];10051006// determine exclusion ranges for font1007// AWT uses separate exclusion range array per component font.1008// 2D packs all range boundaries into one array.1009// Both use separate entries for lower and upper boundary.1010int[][] exclusions = compExclusions[fontIndex];1011int numExclusionRanges = 0;1012for (int i = 0; i < exclusions.length; i++) {1013numExclusionRanges += exclusions[i].length;1014}1015int[] exclusionRanges = new int[numExclusionRanges];1016int[] exclusionRangeLimits = new int[exclusions.length];1017int exclusionRangeIndex = 0;1018int exclusionRangeLimitIndex = 0;1019for (int i = 0; i < exclusions.length; i++) {1020int[] componentRanges = exclusions[i];1021for (int j = 0; j < componentRanges.length; ) {1022int value = componentRanges[j];1023exclusionRanges[exclusionRangeIndex++] = componentRanges[j++];1024exclusionRanges[exclusionRangeIndex++] = componentRanges[j++];1025}1026exclusionRangeLimits[i] = exclusionRangeIndex;1027}1028// other info is per style1029for (int styleIndex = 0; styleIndex < NUM_STYLES; styleIndex++) {1030int maxComponentFontCount = compFontNameIDs[fontIndex][styleIndex].length;1031boolean sawDefaultFontFile = false;1032// fall back fonts listed in the lib/fonts/fallback directory1033if (installedFallbackFontFiles != null) {1034maxComponentFontCount += installedFallbackFontFiles.length;1035}1036String faceName = fontName + "." + styleNames[styleIndex];10371038// determine face names and file names of component fonts1039String[] componentFaceNames = new String[maxComponentFontCount];1040String[] componentFileNames = new String[maxComponentFontCount];10411042int index;1043for (index = 0; index < compFontNameIDs[fontIndex][styleIndex].length; index++) {1044short fontNameID = compFontNameIDs[fontIndex][styleIndex][index];1045short fileNameID = getComponentFileID(fontNameID);1046componentFaceNames[index] = getFaceNameFromComponentFontName(getComponentFontName(fontNameID));1047componentFileNames[index] = mapFileName(getComponentFileName(fileNameID));1048if (componentFileNames[index] == null ||1049needToSearchForFile(componentFileNames[index])) {1050componentFileNames[index] = getFileNameFromComponentFontName(getComponentFontName(fontNameID));1051}1052if (!sawDefaultFontFile &&1053defaultFontFile.equals(componentFileNames[index])) {1054sawDefaultFontFile = true;1055}1056/*1057System.out.println(publicFontNames[fontIndex] + "." + styleNames[styleIndex] + "."1058+ getString(table_scriptIDs[coreScripts[index]]) + "=" + componentFileNames[index]);1059*/1060}10611062//"Lucida Sans Regular" is not in the list, we add it here1063if (!sawDefaultFontFile) {1064int len = 0;1065if (installedFallbackFontFiles != null) {1066len = installedFallbackFontFiles.length;1067}1068if (index + len == maxComponentFontCount) {1069String[] newComponentFaceNames = new String[maxComponentFontCount + 1];1070System.arraycopy(componentFaceNames, 0, newComponentFaceNames, 0, index);1071componentFaceNames = newComponentFaceNames;1072String[] newComponentFileNames = new String[maxComponentFontCount + 1];1073System.arraycopy(componentFileNames, 0, newComponentFileNames, 0, index);1074componentFileNames = newComponentFileNames;1075}1076componentFaceNames[index] = defaultFontFaceName;1077componentFileNames[index] = defaultFontFile;1078index++;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?1379String osName = (String)java.security.AccessController.doPrivileged(1380new java.security.PrivilegedAction() {1381public Object run() {1382return System.getProperty("os.name");1383}1384});13851386//componentFontNameID starts from "1"1387for (int ii = 1; ii < table_filenames.length; ii++) {1388if (table_filenames[ii] == -1) {1389// The corresponding finename entry for a component1390// font name is mandatory on Windows, but it's1391// optional on Solaris and Linux.1392if (osName.contains("Windows")) {1393System.err.println("\n Error: <filename."1394+ getString(table_componentFontNameIDs[ii])1395+ "> entry is missing!!!");1396errors++;1397} else {1398if (verbose && !isEmpty(table_filenames)) {1399System.err.println("\n Note: 'filename' entry is undefined for \""1400+ getString(table_componentFontNameIDs[ii])1401+ "\"");1402}1403}1404}1405}1406for (int ii = 0; ii < table_scriptIDs.length; ii++) {1407short fid = table_scriptFonts[ii];1408if (fid == 0) {1409System.out.println("\n Error: <allfonts."1410+ getString(table_scriptIDs[ii])1411+ "> entry is missing!!!");1412errors++;1413continue;1414} else if (fid < 0) {1415fid = (short)-fid;1416for (int iii = 0; iii < NUM_FONTS; iii++) {1417for (int iij = 0; iij < NUM_STYLES; iij++) {1418int jj = iii * NUM_STYLES + iij;1419short ffid = table_scriptFonts[fid + jj];1420if (ffid == 0) {1421System.err.println("\n Error: <"1422+ getFontName(iii) + "."1423+ getStyleName(iij) + "."1424+ getString(table_scriptIDs[ii])1425+ "> entry is missing!!!");1426errors++;1427}1428}1429}1430}1431}1432if ("SunOS".equals(osName)) {1433for (int ii = 0; ii < table_awtfontpaths.length; ii++) {1434if (table_awtfontpaths[ii] == 0) {1435String script = getString(table_scriptIDs[ii]);1436if (script.contains("lucida") ||1437script.contains("dingbats") ||1438script.contains("symbol")) {1439continue;1440}1441System.err.println("\nError: "1442+ "<awtfontpath."1443+ script1444+ "> entry is missing!!!");1445errors++;1446}1447}1448}1449if (errors != 0) {1450System.err.println("!!THERE ARE " + errors + " ERROR(S) IN "1451+ "THE FONTCONFIG FILE, PLEASE CHECK ITS CONTENT!!\n");1452System.exit(1);1453}1454}14551456private static boolean isEmpty(short[] a) {1457for (short s : a) {1458if (s != -1) {1459return false;1460}1461}1462return true;1463}14641465//dump the fontconfig data tables1466private static void dump() {1467System.out.println("\n----Head Table------------");1468for (int ii = 0; ii < HEAD_LENGTH; ii++) {1469System.out.println(" " + ii + " : " + head[ii]);1470}1471System.out.println("\n----scriptIDs-------------");1472printTable(table_scriptIDs, 0);1473System.out.println("\n----scriptFonts----------------");1474for (int ii = 0; ii < table_scriptIDs.length; ii++) {1475short fid = table_scriptFonts[ii];1476if (fid >= 0) {1477System.out.println(" allfonts."1478+ getString(table_scriptIDs[ii])1479+ "="1480+ getString(table_componentFontNameIDs[fid]));1481}1482}1483for (int ii = 0; ii < table_scriptIDs.length; ii++) {1484short fid = table_scriptFonts[ii];1485if (fid < 0) {1486fid = (short)-fid;1487for (int iii = 0; iii < NUM_FONTS; iii++) {1488for (int iij = 0; iij < NUM_STYLES; iij++) {1489int jj = iii * NUM_STYLES + iij;1490short ffid = table_scriptFonts[fid + jj];1491System.out.println(" "1492+ getFontName(iii) + "."1493+ getStyleName(iij) + "."1494+ getString(table_scriptIDs[ii])1495+ "="1496+ getString(table_componentFontNameIDs[ffid]));1497}1498}14991500}1501}1502System.out.println("\n----elcIDs----------------");1503printTable(table_elcIDs, 0);1504System.out.println("\n----sequences-------------");1505for (int ii = 0; ii< table_elcIDs.length; ii++) {1506System.out.println(" " + ii + "/" + getString((short)table_elcIDs[ii]));1507short[] ss = getShortArray(table_sequences[ii * NUM_FONTS + 0]);1508for (int jj = 0; jj < ss.length; jj++) {1509System.out.println(" " + getString((short)table_scriptIDs[ss[jj]]));1510}1511}1512System.out.println("\n----fontfileNameIDs-------");1513printTable(table_fontfileNameIDs, 0);15141515System.out.println("\n----componentFontNameIDs--");1516printTable(table_componentFontNameIDs, 1);1517System.out.println("\n----filenames-------------");1518for (int ii = 0; ii < table_filenames.length; ii++) {1519if (table_filenames[ii] == -1) {1520System.out.println(" " + ii + " : null");1521} else {1522System.out.println(" " + ii + " : "1523+ getString(table_fontfileNameIDs[table_filenames[ii]]));1524}1525}1526System.out.println("\n----awtfontpaths---------");1527for (int ii = 0; ii < table_awtfontpaths.length; ii++) {1528System.out.println(" " + getString(table_scriptIDs[ii])1529+ " : "1530+ getString(table_awtfontpaths[ii]));1531}1532System.out.println("\n----proportionals--------");1533for (int ii = 0; ii < table_proportionals.length; ii++) {1534System.out.println(" "1535+ getString((short)table_componentFontNameIDs[table_proportionals[ii++]])1536+ " -> "1537+ getString((short)table_componentFontNameIDs[table_proportionals[ii]]));1538}1539int i = 0;1540System.out.println("\n----alphabeticSuffix----");1541while (i < table_alphabeticSuffix.length) {1542System.out.println(" " + getString(table_elcIDs[table_alphabeticSuffix[i++]])1543+ " -> " + getString(table_alphabeticSuffix[i++]));1544}1545System.out.println("\n----String Table---------");1546System.out.println(" stringID: Num =" + table_stringIDs.length);1547System.out.println(" stringTable: Size=" + table_stringTable.length * 2);15481549System.out.println("\n----fallbackScriptIDs---");1550short[] fbsIDs = getShortArray(head[INDEX_fallbackScripts]);1551for (int ii = 0; ii < fbsIDs.length; ii++) {1552System.out.println(" " + getString(table_scriptIDs[fbsIDs[ii]]));1553}1554System.out.println("\n----appendedfontpath-----");1555System.out.println(" " + getString(head[INDEX_appendedfontpath]));1556System.out.println("\n----Version--------------");1557System.out.println(" " + getString(head[INDEX_version]));1558}155915601561//////////////////////////////////////////////////////////////////////1562// Data table access methods //1563//////////////////////////////////////////////////////////////////////15641565/* Return the fontID of the platformFontName defined in this font config1566* by "LogicalFontName.StyleName.CharacterSubsetName" entry or1567* "allfonts.CharacterSubsetName" entry in properties format fc file.1568*/1569protected static short getComponentFontID(short scriptID, int fontIndex, int styleIndex) {1570short fid = table_scriptFonts[scriptID];1571//System.out.println("fid=" + fid + "/ scriptID=" + scriptID + ", fi=" + fontIndex + ", si=" + styleIndex);1572if (fid >= 0) {1573//"allfonts"1574return fid;1575} else {1576return table_scriptFonts[-fid + fontIndex * NUM_STYLES + styleIndex];1577}1578}15791580/* Same as getCompoentFontID() except this method returns the fontID define by1581* "xxxx.motif" entry.1582*/1583protected static short getComponentFontIDMotif(short scriptID, int fontIndex, int styleIndex) {1584if (table_scriptFontsMotif.length == 0) {1585return 0;1586}1587short fid = table_scriptFontsMotif[scriptID];1588if (fid >= 0) {1589//"allfonts" > 0 or "not defined" == 01590return fid;1591} else {1592return table_scriptFontsMotif[-fid + fontIndex * NUM_STYLES + styleIndex];1593}1594}15951596private static int[] getExclusionRanges(short scriptID) {1597short exID = table_exclusions[scriptID];1598if (exID == 0) {1599return EMPTY_INT_ARRAY;1600} else {1601char[] exChar = getString(exID).toCharArray();1602int[] exInt = new int[exChar.length / 2];1603int i = 0;1604for (int j = 0; j < exInt.length; j++) {1605exInt[j] = (exChar[i++] << 16) + (exChar[i++] & 0xffff);1606}1607return exInt;1608}1609}16101611private static boolean contains(short IDs[], short id, int limit) {1612for (int i = 0; i < limit; i++) {1613if (IDs[i] == id) {1614return true;1615}1616}1617return false;1618}16191620/* Return the PlatformFontName from its fontID*/1621protected static String getComponentFontName(short id) {1622if (id < 0) {1623return null;1624}1625return getString(table_componentFontNameIDs[id]);1626}16271628private static String getComponentFileName(short id) {1629if (id < 0) {1630return null;1631}1632return getString(table_fontfileNameIDs[id]);1633}16341635//componentFontID -> componentFileID1636private static short getComponentFileID(short nameID) {1637return table_filenames[nameID];1638}16391640private static String getScriptName(short scriptID) {1641return getString(table_scriptIDs[scriptID]);1642}16431644private HashMap<String, Short> reorderScripts;1645protected short[] getCoreScripts(int fontIndex) {1646short elc = getInitELC();1647/*1648System.out.println("getCoreScripts: elc=" + elc + ", fontIndex=" + fontIndex);1649short[] ss = getShortArray(table_sequences[elc * NUM_FONTS + fontIndex]);1650for (int i = 0; i < ss.length; i++) {1651System.out.println(" " + getString((short)table_scriptIDs[ss[i]]));1652}1653*/1654short[] scripts = getShortArray(table_sequences[elc * NUM_FONTS + fontIndex]);1655if (preferLocaleFonts) {1656if (reorderScripts == null) {1657reorderScripts = new HashMap<String, Short>();1658}1659String[] ss = new String[scripts.length];1660for (int i = 0; i < ss.length; i++) {1661ss[i] = getScriptName(scripts[i]);1662reorderScripts.put(ss[i], scripts[i]);1663}1664reorderSequenceForLocale(ss);1665for (int i = 0; i < ss.length; i++) {1666scripts[i] = reorderScripts.get(ss[i]);1667}1668}1669return scripts;1670}16711672private static short[] getFallbackScripts() {1673return getShortArray(head[INDEX_fallbackScripts]);1674}16751676private static void printTable(short[] list, int start) {1677for (int i = start; i < list.length; i++) {1678System.out.println(" " + i + " : " + getString(list[i]));1679}1680}16811682private static short[] readShortTable(DataInputStream in, int len )1683throws IOException {1684if (len == 0) {1685return EMPTY_SHORT_ARRAY;1686}1687short[] data = new short[len];1688byte[] bb = new byte[len * 2];1689in.read(bb);1690int i = 0,j = 0;1691while (i < len) {1692data[i++] = (short)(bb[j++] << 8 | (bb[j++] & 0xff));1693}1694return data;1695}16961697private static void writeShortTable(DataOutputStream out, short[] data)1698throws IOException {1699for (short val : data) {1700out.writeShort(val);1701}1702}17031704private static short[] toList(HashMap<String, Short> map) {1705short[] list = new short[map.size()];1706Arrays.fill(list, (short) -1);1707for (Entry<String, Short> entry : map.entrySet()) {1708list[entry.getValue()] = getStringID(entry.getKey());1709}1710return list;1711}17121713//runtime cache1714private static String[] stringCache;1715protected static String getString(short stringID) {1716if (stringID == 0)1717return null;1718/*1719if (loadingProperties) {1720return stringTable.substring(stringIDs[stringID],1721stringIDs[stringID+1]);1722}1723*/1724//sync if we want it to be MT-enabled1725if (stringCache[stringID] == null){1726stringCache[stringID] =1727new String (table_stringTable,1728table_stringIDs[stringID],1729table_stringIDs[stringID+1] - table_stringIDs[stringID]);1730}1731return stringCache[stringID];1732}17331734private static short[] getShortArray(short shortArrayID) {1735String s = getString(shortArrayID);1736char[] cc = s.toCharArray();1737short[] ss = new short[cc.length];1738for (int i = 0; i < cc.length; i++) {1739ss[i] = (short)(cc[i] & 0xffff);1740}1741return ss;1742}17431744private static short getStringID(String s) {1745if (s == null) {1746return (short)0;1747}1748short pos0 = (short)stringTable.length();1749stringTable.append(s);1750short pos1 = (short)stringTable.length();17511752stringIDs[stringIDNum] = pos0;1753stringIDs[stringIDNum + 1] = pos1;1754stringIDNum++;1755if (stringIDNum + 1 >= stringIDs.length) {1756short[] tmp = new short[stringIDNum + 1000];1757System.arraycopy(stringIDs, 0, tmp, 0, stringIDNum);1758stringIDs = tmp;1759}1760return (short)(stringIDNum - 1);1761}17621763private static short getShortArrayID(short sa[]) {1764char[] cc = new char[sa.length];1765for (int i = 0; i < sa.length; i ++) {1766cc[i] = (char)sa[i];1767}1768String s = new String(cc);1769return getStringID(s);1770}17711772//utility "empty" objects1773private static final int[] EMPTY_INT_ARRAY = new int[0];1774private static final String[] EMPTY_STRING_ARRAY = new String[0];1775private static final short[] EMPTY_SHORT_ARRAY = new short[0];1776private static final String UNDEFINED_COMPONENT_FONT = "unknown";17771778//////////////////////////////////////////////////////////////////////////1779//Convert the FontConfig data in Properties file to binary data tables //1780//////////////////////////////////////////////////////////////////////////1781static class PropertiesHandler {1782public void load(InputStream in) throws IOException {1783initLogicalNameStyle();1784initHashMaps();1785FontProperties fp = new FontProperties();1786fp.load(in);1787initBinaryTable();1788}17891790private void initBinaryTable() {1791//(0)1792head = new short[HEAD_LENGTH];1793head[INDEX_scriptIDs] = (short)HEAD_LENGTH;17941795table_scriptIDs = toList(scriptIDs);1796//(1)a: scriptAllfonts scriptID/allfonts -> componentFontNameID1797// b: scriptFonts scriptID -> componentFontNameID[20]1798//if we have a "allfonts.script" def, then we just put1799//the "-platformFontID" value in the slot, otherwise the slot1800//value is "offset" which "offset" is where 20 entries located1801//in the table attached.1802head[INDEX_scriptFonts] = (short)(head[INDEX_scriptIDs] + table_scriptIDs.length);1803int len = table_scriptIDs.length + scriptFonts.size() * 20;1804table_scriptFonts = new short[len];18051806for (Entry<Short, Short> entry : scriptAllfonts.entrySet()) {1807table_scriptFonts[entry.getKey().intValue()] = entry.getValue();1808}1809int off = table_scriptIDs.length;1810for (Entry<Short, Short[]> entry : scriptFonts.entrySet()) {1811table_scriptFonts[entry.getKey().intValue()] = (short)-off;1812Short[] v = entry.getValue();1813for (int i = 0; i < 20; i++) {1814if (v[i] != null) {1815table_scriptFonts[off++] = v[i];1816} else {1817table_scriptFonts[off++] = 0;1818}1819}1820}18211822//(2)1823head[INDEX_elcIDs] = (short)(head[INDEX_scriptFonts] + table_scriptFonts.length);1824table_elcIDs = toList(elcIDs);18251826//(3) sequences elcID -> XXXX[1|5] -> scriptID[]1827head[INDEX_sequences] = (short)(head[INDEX_elcIDs] + table_elcIDs.length);1828table_sequences = new short[elcIDs.size() * NUM_FONTS];1829for (Entry<Short, short[]> entry : sequences.entrySet()) {1830//table_sequences[entry.getKey().intValue()] = (short)-off;1831int k = entry.getKey().intValue();1832short[] v = entry.getValue();1833/*1834System.out.println("elc=" + k + "/" + getString((short)table_elcIDs[k]));1835short[] ss = getShortArray(v[0]);1836for (int i = 0; i < ss.length; i++) {1837System.out.println(" " + getString((short)table_scriptIDs[ss[i]]));1838}1839*/1840if (v.length == 1) {1841//the "allfonts" entries1842for (int i = 0; i < NUM_FONTS; i++) {1843table_sequences[k * NUM_FONTS + i] = v[0];1844}1845} else {1846for (int i = 0; i < NUM_FONTS; i++) {1847table_sequences[k * NUM_FONTS + i] = v[i];1848}1849}1850}1851//(4)1852head[INDEX_fontfileNameIDs] = (short)(head[INDEX_sequences] + table_sequences.length);1853table_fontfileNameIDs = toList(fontfileNameIDs);18541855//(5)1856head[INDEX_componentFontNameIDs] = (short)(head[INDEX_fontfileNameIDs] + table_fontfileNameIDs.length);1857table_componentFontNameIDs = toList(componentFontNameIDs);18581859//(6)componentFontNameID -> filenameID1860head[INDEX_filenames] = (short)(head[INDEX_componentFontNameIDs] + table_componentFontNameIDs.length);1861table_filenames = new short[table_componentFontNameIDs.length];1862Arrays.fill(table_filenames, (short) -1);18631864for (Entry<Short, Short> entry : filenames.entrySet()) {1865table_filenames[entry.getKey()] = entry.getValue();1866}18671868//(7)scriptID-> awtfontpath1869//the paths are stored as scriptID -> stringID in awtfontpahts1870head[INDEX_awtfontpaths] = (short)(head[INDEX_filenames] + table_filenames.length);1871table_awtfontpaths = new short[table_scriptIDs.length];1872for (Entry<Short, Short> entry : awtfontpaths.entrySet()) {1873table_awtfontpaths[entry.getKey()] = entry.getValue();1874}18751876//(8)exclusions1877head[INDEX_exclusions] = (short)(head[INDEX_awtfontpaths] + table_awtfontpaths.length);1878table_exclusions = new short[scriptIDs.size()];1879for (Entry<Short, int[]> entry : exclusions.entrySet()) {1880int[] exI = entry.getValue();1881char[] exC = new char[exI.length * 2];1882int j = 0;1883for (int i = 0; i < exI.length; i++) {1884exC[j++] = (char) (exI[i] >> 16);1885exC[j++] = (char) (exI[i] & 0xffff);1886}1887table_exclusions[entry.getKey()] = getStringID(new String (exC));1888}1889//(9)proportionals1890head[INDEX_proportionals] = (short)(head[INDEX_exclusions] + table_exclusions.length);1891table_proportionals = new short[proportionals.size() * 2];1892int j = 0;1893for (Entry<Short, Short> entry : proportionals.entrySet()) {1894table_proportionals[j++] = entry.getKey();1895table_proportionals[j++] = entry.getValue();1896}18971898//(10) see (1) for info, the only difference is "xxx.motif"1899head[INDEX_scriptFontsMotif] = (short)(head[INDEX_proportionals] + table_proportionals.length);1900if (scriptAllfontsMotif.size() != 0 || scriptFontsMotif.size() != 0) {1901len = table_scriptIDs.length + scriptFontsMotif.size() * 20;1902table_scriptFontsMotif = new short[len];19031904for (Entry<Short, Short> entry : scriptAllfontsMotif.entrySet()) {1905table_scriptFontsMotif[entry.getKey().intValue()] =1906(short)entry.getValue();1907}1908off = table_scriptIDs.length;1909for (Entry<Short, Short[]> entry : scriptFontsMotif.entrySet()) {1910table_scriptFontsMotif[entry.getKey().intValue()] = (short)-off;1911Short[] v = entry.getValue();1912int i = 0;1913while (i < 20) {1914if (v[i] != null) {1915table_scriptFontsMotif[off++] = v[i];1916} else {1917table_scriptFontsMotif[off++] = 0;1918}1919i++;1920}1921}1922} else {1923table_scriptFontsMotif = EMPTY_SHORT_ARRAY;1924}19251926//(11)short[] alphabeticSuffix1927head[INDEX_alphabeticSuffix] = (short)(head[INDEX_scriptFontsMotif] + table_scriptFontsMotif.length);1928table_alphabeticSuffix = new short[alphabeticSuffix.size() * 2];1929j = 0;1930for (Entry<Short, Short> entry : alphabeticSuffix.entrySet()) {1931table_alphabeticSuffix[j++] = entry.getKey();1932table_alphabeticSuffix[j++] = entry.getValue();1933}19341935//(15)short[] fallbackScriptIDs; just put the ID in head1936head[INDEX_fallbackScripts] = getShortArrayID(fallbackScriptIDs);19371938//(16)appendedfontpath1939head[INDEX_appendedfontpath] = getStringID(appendedfontpath);19401941//(17)version1942head[INDEX_version] = getStringID(version);19431944//(12)short[] StringIDs1945head[INDEX_stringIDs] = (short)(head[INDEX_alphabeticSuffix] + table_alphabeticSuffix.length);1946table_stringIDs = new short[stringIDNum + 1];1947System.arraycopy(stringIDs, 0, table_stringIDs, 0, stringIDNum + 1);19481949//(13)StringTable1950head[INDEX_stringTable] = (short)(head[INDEX_stringIDs] + stringIDNum + 1);1951table_stringTable = stringTable.toString().toCharArray();1952//(14)1953head[INDEX_TABLEEND] = (short)(head[INDEX_stringTable] + stringTable.length());19541955//StringTable cache1956stringCache = new String[table_stringIDs.length];1957}19581959//////////////////////////////////////////////1960private HashMap<String, Short> scriptIDs;1961//elc -> Encoding.Language.Country1962private HashMap<String, Short> elcIDs;1963//componentFontNameID starts from "1", "0" reserves for "undefined"1964private HashMap<String, Short> componentFontNameIDs;1965private HashMap<String, Short> fontfileNameIDs;1966private HashMap<String, Integer> logicalFontIDs;1967private HashMap<String, Integer> fontStyleIDs;19681969//componentFontNameID -> fontfileNameID1970private HashMap<Short, Short> filenames;19711972//elcID -> allfonts/logicalFont -> scriptID list1973//(1)if we have a "allfonts", then the length of the1974// value array is "1", otherwise it's 5, each font1975// must have their own individual entry.1976//scriptID list "short[]" is stored as an ID1977private HashMap<Short, short[]> sequences;19781979//scriptID ->logicFontID/fontStyleID->componentFontNameID,1980//a 20-entry array (5-name x 4-style) for each script1981private HashMap<Short, Short[]> scriptFonts;19821983//scriptID -> componentFontNameID1984private HashMap<Short, Short> scriptAllfonts;19851986//scriptID -> exclusionRanges[]1987private HashMap<Short, int[]> exclusions;19881989//scriptID -> fontpath1990private HashMap<Short, Short> awtfontpaths;19911992//fontID -> fontID1993private HashMap<Short, Short> proportionals;19941995//scriptID -> componentFontNameID1996private HashMap<Short, Short> scriptAllfontsMotif;19971998//scriptID ->logicFontID/fontStyleID->componentFontNameID,1999private HashMap<Short, Short[]> scriptFontsMotif;20002001//elcID -> stringID of alphabetic/XXXX2002private HashMap<Short, Short> alphabeticSuffix;20032004private short[] fallbackScriptIDs;2005private String version;2006private String appendedfontpath;20072008private void initLogicalNameStyle() {2009logicalFontIDs = new HashMap<String, Integer>();2010fontStyleIDs = new HashMap<String, Integer>();2011logicalFontIDs.put("serif", 0);2012logicalFontIDs.put("sansserif", 1);2013logicalFontIDs.put("monospaced", 2);2014logicalFontIDs.put("dialog", 3);2015logicalFontIDs.put("dialoginput",4);2016fontStyleIDs.put("plain", 0);2017fontStyleIDs.put("bold", 1);2018fontStyleIDs.put("italic", 2);2019fontStyleIDs.put("bolditalic", 3);2020}20212022private void initHashMaps() {2023scriptIDs = new HashMap<String, Short>();2024elcIDs = new HashMap<String, Short>();2025componentFontNameIDs = new HashMap<String, Short>();2026/*Init these tables to allow componentFontNameID, fontfileNameIDs2027to start from "1".2028*/2029componentFontNameIDs.put("", Short.valueOf((short)0));20302031fontfileNameIDs = new HashMap<String, Short>();2032filenames = new HashMap<Short, Short>();2033sequences = new HashMap<Short, short[]>();2034scriptFonts = new HashMap<Short, Short[]>();2035scriptAllfonts = new HashMap<Short, Short>();2036exclusions = new HashMap<Short, int[]>();2037awtfontpaths = new HashMap<Short, Short>();2038proportionals = new HashMap<Short, Short>();2039scriptFontsMotif = new HashMap<Short, Short[]>();2040scriptAllfontsMotif = new HashMap<Short, Short>();2041alphabeticSuffix = new HashMap<Short, Short>();2042fallbackScriptIDs = EMPTY_SHORT_ARRAY;2043/*2044version2045appendedfontpath2046*/2047}20482049private int[] parseExclusions(String key, String exclusions) {2050if (exclusions == null) {2051return EMPTY_INT_ARRAY;2052}2053// range format is xxxx-XXXX,yyyyyy-YYYYYY,.....2054int numExclusions = 1;2055int pos = 0;2056while ((pos = exclusions.indexOf(',', pos)) != -1) {2057numExclusions++;2058pos++;2059}2060int[] exclusionRanges = new int[numExclusions * 2];2061pos = 0;2062int newPos = 0;2063for (int j = 0; j < numExclusions * 2; ) {2064String lower, upper;2065int lo = 0, up = 0;2066try {2067newPos = exclusions.indexOf('-', pos);2068lower = exclusions.substring(pos, newPos);2069pos = newPos + 1;2070newPos = exclusions.indexOf(',', pos);2071if (newPos == -1) {2072newPos = exclusions.length();2073}2074upper = exclusions.substring(pos, newPos);2075pos = newPos + 1;2076int lowerLength = lower.length();2077int upperLength = upper.length();2078if (lowerLength != 4 && lowerLength != 62079|| upperLength != 4 && upperLength != 6) {2080throw new Exception();2081}2082lo = Integer.parseInt(lower, 16);2083up = Integer.parseInt(upper, 16);2084if (lo > up) {2085throw new Exception();2086}2087} catch (Exception e) {2088if (FontUtilities.debugFonts() &&2089logger != null) {2090logger.config("Failed parsing " + key +2091" property of font configuration.");20922093}2094return EMPTY_INT_ARRAY;2095}2096exclusionRanges[j++] = lo;2097exclusionRanges[j++] = up;2098}2099return exclusionRanges;2100}21012102private Short getID(HashMap<String, Short> map, String key) {2103Short ret = map.get(key);2104if ( ret == null) {2105map.put(key, (short)map.size());2106return map.get(key);2107}2108return ret;2109}21102111class FontProperties extends Properties {2112public synchronized Object put(Object k, Object v) {2113parseProperty((String)k, (String)v);2114return null;2115}2116}21172118private void parseProperty(String key, String value) {2119if (key.startsWith("filename.")) {2120//the only special case is "MingLiu_HKSCS" which has "_" in its2121//facename, we don't want to replace the "_" with " "2122key = key.substring(9);2123if (!"MingLiU_HKSCS".equals(key)) {2124key = key.replace('_', ' ');2125}2126Short faceID = getID(componentFontNameIDs, key);2127Short fileID = getID(fontfileNameIDs, value);2128//System.out.println("faceID=" + faceID + "/" + key + " -> "2129// + "fileID=" + fileID + "/" + value);2130filenames.put(faceID, fileID);2131} else if (key.startsWith("exclusion.")) {2132key = key.substring(10);2133exclusions.put(getID(scriptIDs,key), parseExclusions(key,value));2134} else if (key.startsWith("sequence.")) {2135key = key.substring(9);2136boolean hasDefault = false;2137boolean has1252 = false;21382139//get the scriptID list2140String[] ss = (String[])splitSequence(value).toArray(EMPTY_STRING_ARRAY);2141short [] sa = new short[ss.length];2142for (int i = 0; i < ss.length; i++) {2143if ("alphabetic/default".equals(ss[i])) {2144//System.out.println(key + " -> " + ss[i]);2145ss[i] = "alphabetic";2146hasDefault = true;2147} else if ("alphabetic/1252".equals(ss[i])) {2148//System.out.println(key + " -> " + ss[i]);2149ss[i] = "alphabetic";2150has1252 = true;2151}2152sa[i] = getID(scriptIDs, ss[i]).shortValue();2153//System.out.println("scriptID=" + si[i] + "/" + ss[i]);2154}2155//convert the "short[] -> string -> stringID"2156short scriptArrayID = getShortArrayID(sa);2157Short elcID = null;2158int dot = key.indexOf('.');2159if (dot == -1) {2160if ("fallback".equals(key)) {2161fallbackScriptIDs = sa;2162return;2163}2164if ("allfonts".equals(key)) {2165elcID = getID(elcIDs, "NULL.NULL.NULL");2166} else {2167if (logger != null) {2168logger.config("Error sequence def: <sequence." + key + ">");2169}2170return;2171}2172} else {2173elcID = getID(elcIDs, key.substring(dot + 1));2174//System.out.println("elcID=" + elcID + "/" + key.substring(dot + 1));2175key = key.substring(0, dot);2176}2177short[] scriptArrayIDs = null;2178if ("allfonts".equals(key)) {2179scriptArrayIDs = new short[1];2180scriptArrayIDs[0] = scriptArrayID;2181} else {2182scriptArrayIDs = sequences.get(elcID);2183if (scriptArrayIDs == null) {2184scriptArrayIDs = new short[5];2185}2186Integer fid = logicalFontIDs.get(key);2187if (fid == null) {2188if (logger != null) {2189logger.config("Unrecognizable logicfont name " + key);2190}2191return;2192}2193//System.out.println("sequence." + key + "/" + id);2194scriptArrayIDs[fid.intValue()] = scriptArrayID;2195}2196sequences.put(elcID, scriptArrayIDs);2197if (hasDefault) {2198alphabeticSuffix.put(elcID, getStringID("default"));2199} else2200if (has1252) {2201alphabeticSuffix.put(elcID, getStringID("1252"));2202}2203} else if (key.startsWith("allfonts.")) {2204key = key.substring(9);2205if (key.endsWith(".motif")) {2206key = key.substring(0, key.length() - 6);2207//System.out.println("motif: all." + key + "=" + value);2208scriptAllfontsMotif.put(getID(scriptIDs,key), getID(componentFontNameIDs,value));2209} else {2210scriptAllfonts.put(getID(scriptIDs,key), getID(componentFontNameIDs,value));2211}2212} else if (key.startsWith("awtfontpath.")) {2213key = key.substring(12);2214//System.out.println("scriptID=" + getID(scriptIDs, key) + "/" + key);2215awtfontpaths.put(getID(scriptIDs, key), getStringID(value));2216} else if ("version".equals(key)) {2217version = value;2218} else if ("appendedfontpath".equals(key)) {2219appendedfontpath = value;2220} else if (key.startsWith("proportional.")) {2221key = key.substring(13).replace('_', ' ');2222//System.out.println(key + "=" + value);2223proportionals.put(getID(componentFontNameIDs, key),2224getID(componentFontNameIDs, value));2225} else {2226//"name.style.script(.motif)", we don't care anything else2227int dot1, dot2;2228boolean isMotif = false;22292230dot1 = key.indexOf('.');2231if (dot1 == -1) {2232if (logger != null) {2233logger.config("Failed parsing " + key +2234" property of font configuration.");22352236}2237return;2238}2239dot2 = key.indexOf('.', dot1 + 1);2240if (dot2 == -1) {2241if (logger != null) {2242logger.config("Failed parsing " + key +2243" property of font configuration.");22442245}2246return;2247}2248if (key.endsWith(".motif")) {2249key = key.substring(0, key.length() - 6);2250isMotif = true;2251//System.out.println("motif: " + key + "=" + value);2252}2253Integer nameID = logicalFontIDs.get(key.substring(0, dot1));2254Integer styleID = fontStyleIDs.get(key.substring(dot1+1, dot2));2255Short scriptID = getID(scriptIDs, key.substring(dot2 + 1));2256if (nameID == null || styleID == null) {2257if (logger != null) {2258logger.config("unrecognizable logicfont name/style at " + key);2259}2260return;2261}2262Short[] pnids;2263if (isMotif) {2264pnids = scriptFontsMotif.get(scriptID);2265} else {2266pnids = scriptFonts.get(scriptID);2267}2268if (pnids == null) {2269pnids = new Short[20];2270}2271pnids[nameID.intValue() * NUM_STYLES + styleID.intValue()]2272= getID(componentFontNameIDs, value);2273/*2274System.out.println("key=" + key + "/<" + nameID + "><" + styleID2275+ "><" + scriptID + ">=" + value2276+ "/" + getID(componentFontNameIDs, value));2277*/2278if (isMotif) {2279scriptFontsMotif.put(scriptID, pnids);2280} else {2281scriptFonts.put(scriptID, pnids);2282}2283}2284}2285}2286}228722882289