/src/share/classes/sun/awt/FontConfiguration.java
Java | 2287 lines | 1648 code | 191 blank | 448 comment | 394 complexity | 3461265e645d057859758ca155b1d540 MD5 | raw file
Possible License(s): GPL-2.0, BSD-3-Clause-No-Nuclear-License-2014, LGPL-3.0
- /*
- * Copyright (c) 1996, 2011, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
- package sun.awt;
- import java.awt.Font;
- import java.io.DataInputStream;
- import java.io.DataOutputStream;
- import java.io.File;
- import java.io.FileInputStream;
- import java.io.InputStream;
- import java.io.IOException;
- import java.io.OutputStream;
- import java.nio.charset.Charset;
- import java.nio.charset.CharsetEncoder;
- import java.security.AccessController;
- import java.security.PrivilegedAction;
- import java.util.Arrays;
- import java.util.HashMap;
- import java.util.HashSet;
- import java.util.Hashtable;
- import java.util.Locale;
- import java.util.Map.Entry;
- import java.util.Properties;
- import java.util.Set;
- import java.util.Vector;
- import sun.font.CompositeFontDescriptor;
- import sun.font.SunFontManager;
- import sun.font.FontManagerFactory;
- import sun.font.FontUtilities;
- import sun.util.logging.PlatformLogger;
- /**
- * Provides the definitions of the five logical fonts: Serif, SansSerif,
- * Monospaced, Dialog, and DialogInput. The necessary information
- * is obtained from fontconfig files.
- */
- public abstract class FontConfiguration {
- //static global runtime env
- protected static String osVersion;
- protected static String osName;
- protected static String encoding; // canonical name of default nio charset
- protected static Locale startupLocale = null;
- protected static Hashtable localeMap = null;
- private static FontConfiguration fontConfig;
- private static PlatformLogger logger;
- protected static boolean isProperties = true;
- protected SunFontManager fontManager;
- protected boolean preferLocaleFonts;
- protected boolean preferPropFonts;
- private File fontConfigFile;
- private boolean foundOsSpecificFile;
- private boolean inited;
- private String javaLib;
- /* A default FontConfiguration must be created before an alternate
- * one to ensure proper static initialisation takes place.
- */
- public FontConfiguration(SunFontManager fm) {
- if (FontUtilities.debugFonts()) {
- FontUtilities.getLogger()
- .info("Creating standard Font Configuration");
- }
- if (FontUtilities.debugFonts() && logger == null) {
- logger = PlatformLogger.getLogger("sun.awt.FontConfiguration");
- }
- fontManager = fm;
- setOsNameAndVersion(); /* static initialization */
- setEncoding(); /* static initialization */
- /* Separating out the file location from the rest of the
- * initialisation, so the caller has the option of doing
- * something else if a suitable file isn't found.
- */
- findFontConfigFile();
- }
- public synchronized boolean init() {
- if (!inited) {
- this.preferLocaleFonts = false;
- this.preferPropFonts = false;
- setFontConfiguration();
- readFontConfigFile(fontConfigFile);
- initFontConfig();
- inited = true;
- }
- return true;
- }
- public FontConfiguration(SunFontManager fm,
- boolean preferLocaleFonts,
- boolean preferPropFonts) {
- fontManager = fm;
- if (FontUtilities.debugFonts()) {
- FontUtilities.getLogger()
- .info("Creating alternate Font Configuration");
- }
- this.preferLocaleFonts = preferLocaleFonts;
- this.preferPropFonts = preferPropFonts;
- /* fontConfig should be initialised by default constructor, and
- * its data tables can be shared, since readFontConfigFile doesn't
- * update any other state. Also avoid a doPrivileged block.
- */
- initFontConfig();
- }
- /**
- * Fills in this instance's osVersion and osName members. By
- * default uses the system properties os.name and os.version;
- * subclasses may override.
- */
- protected void setOsNameAndVersion() {
- osName = System.getProperty("os.name");
- osVersion = System.getProperty("os.version");
- }
- private void setEncoding() {
- encoding = Charset.defaultCharset().name();
- startupLocale = SunToolkit.getStartupLocale();
- }
- /////////////////////////////////////////////////////////////////////
- // methods for loading the FontConfig file //
- /////////////////////////////////////////////////////////////////////
- public boolean foundOsSpecificFile() {
- return foundOsSpecificFile;
- }
- /* Smoke test to see if we can trust this configuration by testing if
- * the first slot of a composite font maps to an installed file.
- */
- public boolean fontFilesArePresent() {
- init();
- short fontNameID = compFontNameIDs[0][0][0];
- short fileNameID = getComponentFileID(fontNameID);
- final String fileName = mapFileName(getComponentFileName(fileNameID));
- Boolean exists = (Boolean)java.security.AccessController.doPrivileged(
- new java.security.PrivilegedAction() {
- public Object run() {
- try {
- File f = new File(fileName);
- return Boolean.valueOf(f.exists());
- }
- catch (Exception e) {
- return false;
- }
- }
- });
- return exists.booleanValue();
- }
- private void findFontConfigFile() {
- foundOsSpecificFile = true; // default assumption.
- String javaHome = System.getProperty("java.home");
- if (javaHome == null) {
- throw new Error("java.home property not set");
- }
- javaLib = javaHome + File.separator + "lib";
- String userConfigFile = System.getProperty("sun.awt.fontconfig");
- if (userConfigFile != null) {
- fontConfigFile = new File(userConfigFile);
- } else {
- fontConfigFile = findFontConfigFile(javaLib);
- }
- }
- private void readFontConfigFile(File f) {
- /* This is invoked here as readFontConfigFile is only invoked
- * once per VM, and always in a privileged context, thus the
- * directory containing installed fall back fonts is accessed
- * from this context
- */
- getInstalledFallbackFonts(javaLib);
- if (f != null) {
- try {
- FileInputStream in = new FileInputStream(f.getPath());
- if (isProperties) {
- loadProperties(in);
- } else {
- loadBinary(in);
- }
- in.close();
- if (FontUtilities.debugFonts()) {
- logger.config("Read logical font configuration from " + f);
- }
- } catch (IOException e) {
- if (FontUtilities.debugFonts()) {
- logger.config("Failed to read logical font configuration from " + f);
- }
- }
- }
- String version = getVersion();
- if (!"1".equals(version) && FontUtilities.debugFonts()) {
- logger.config("Unsupported fontconfig version: " + version);
- }
- }
- protected void getInstalledFallbackFonts(String javaLib) {
- String fallbackDirName = javaLib + File.separator +
- "fonts" + File.separator + "fallback";
- File fallbackDir = new File(fallbackDirName);
- if (fallbackDir.exists() && fallbackDir.isDirectory()) {
- String[] ttfs = fallbackDir.list(fontManager.getTrueTypeFilter());
- String[] t1s = fallbackDir.list(fontManager.getType1Filter());
- int numTTFs = (ttfs == null) ? 0 : ttfs.length;
- int numT1s = (t1s == null) ? 0 : t1s.length;
- int len = numTTFs + numT1s;
- if (numTTFs + numT1s == 0) {
- return;
- }
- installedFallbackFontFiles = new String[len];
- for (int i=0; i<numTTFs; i++) {
- installedFallbackFontFiles[i] =
- fallbackDir + File.separator + ttfs[i];
- }
- for (int i=0; i<numT1s; i++) {
- installedFallbackFontFiles[i+numTTFs] =
- fallbackDir + File.separator + t1s[i];
- }
- fontManager.registerFontsInDir(fallbackDirName);
- }
- }
- private File findImpl(String fname) {
- File f = new File(fname + ".properties");
- if (f.canRead()) {
- isProperties = true;
- return f;
- }
- f = new File(fname + ".bfc");
- if (f.canRead()) {
- isProperties = false;
- return f;
- }
- return null;
- }
- private File findFontConfigFile(String javaLib) {
- String baseName = javaLib + File.separator + "fontconfig";
- File configFile;
- String osMajorVersion = null;
- if (osVersion != null && osName != null) {
- configFile = findImpl(baseName + "." + osName + "." + osVersion);
- if (configFile != null) {
- return configFile;
- }
- int decimalPointIndex = osVersion.indexOf(".");
- if (decimalPointIndex != -1) {
- osMajorVersion = osVersion.substring(0, osVersion.indexOf("."));
- configFile = findImpl(baseName + "." + osName + "." + osMajorVersion);
- if (configFile != null) {
- return configFile;
- }
- }
- }
- if (osName != null) {
- configFile = findImpl(baseName + "." + osName);
- if (configFile != null) {
- return configFile;
- }
- }
- if (osVersion != null) {
- configFile = findImpl(baseName + "." + osVersion);
- if (configFile != null) {
- return configFile;
- }
- if (osMajorVersion != null) {
- configFile = findImpl(baseName + "." + osMajorVersion);
- if (configFile != null) {
- return configFile;
- }
- }
- }
- foundOsSpecificFile = false;
- configFile = findImpl(baseName);
- if (configFile != null) {
- return configFile;
- }
- return null;
- }
- /* Initialize the internal data tables from binary format font
- * configuration file.
- */
- public static void loadBinary(InputStream inStream) throws IOException {
- DataInputStream in = new DataInputStream(inStream);
- head = readShortTable(in, HEAD_LENGTH);
- int[] tableSizes = new int[INDEX_TABLEEND];
- for (int i = 0; i < INDEX_TABLEEND; i++) {
- tableSizes[i] = head[i + 1] - head[i];
- }
- table_scriptIDs = readShortTable(in, tableSizes[INDEX_scriptIDs]);
- table_scriptFonts = readShortTable(in, tableSizes[INDEX_scriptFonts]);
- table_elcIDs = readShortTable(in, tableSizes[INDEX_elcIDs]);
- table_sequences = readShortTable(in, tableSizes[INDEX_sequences]);
- table_fontfileNameIDs = readShortTable(in, tableSizes[INDEX_fontfileNameIDs]);
- table_componentFontNameIDs = readShortTable(in, tableSizes[INDEX_componentFontNameIDs]);
- table_filenames = readShortTable(in, tableSizes[INDEX_filenames]);
- table_awtfontpaths = readShortTable(in, tableSizes[INDEX_awtfontpaths]);
- table_exclusions = readShortTable(in, tableSizes[INDEX_exclusions]);
- table_proportionals = readShortTable(in, tableSizes[INDEX_proportionals]);
- table_scriptFontsMotif = readShortTable(in, tableSizes[INDEX_scriptFontsMotif]);
- table_alphabeticSuffix = readShortTable(in, tableSizes[INDEX_alphabeticSuffix]);
- table_stringIDs = readShortTable(in, tableSizes[INDEX_stringIDs]);
- //StringTable cache
- stringCache = new String[table_stringIDs.length + 1];
- int len = tableSizes[INDEX_stringTable];
- byte[] bb = new byte[len * 2];
- table_stringTable = new char[len];
- in.read(bb);
- int i = 0, j = 0;
- while (i < len) {
- table_stringTable[i++] = (char)(bb[j++] << 8 | (bb[j++] & 0xff));
- }
- if (verbose) {
- dump();
- }
- }
- /* Generate a binary format font configuration from internal data
- * tables.
- */
- public static void saveBinary(OutputStream out) throws IOException {
- sanityCheck();
- DataOutputStream dataOut = new DataOutputStream(out);
- writeShortTable(dataOut, head);
- writeShortTable(dataOut, table_scriptIDs);
- writeShortTable(dataOut, table_scriptFonts);
- writeShortTable(dataOut, table_elcIDs);
- writeShortTable(dataOut, table_sequences);
- writeShortTable(dataOut, table_fontfileNameIDs);
- writeShortTable(dataOut, table_componentFontNameIDs);
- writeShortTable(dataOut, table_filenames);
- writeShortTable(dataOut, table_awtfontpaths);
- writeShortTable(dataOut, table_exclusions);
- writeShortTable(dataOut, table_proportionals);
- writeShortTable(dataOut, table_scriptFontsMotif);
- writeShortTable(dataOut, table_alphabeticSuffix);
- writeShortTable(dataOut, table_stringIDs);
- //stringTable
- dataOut.writeChars(new String(table_stringTable));
- out.close();
- if (verbose) {
- dump();
- }
- }
- //private static boolean loadingProperties;
- private static short stringIDNum;
- private static short[] stringIDs;
- private static StringBuilder stringTable;
- public static void loadProperties(InputStream in) throws IOException {
- //loadingProperties = true;
- //StringID starts from "1", "0" is reserved for "not defined"
- stringIDNum = 1;
- stringIDs = new short[1000];
- stringTable = new StringBuilder(4096);
- if (verbose && logger == null) {
- logger = PlatformLogger.getLogger("sun.awt.FontConfiguration");
- }
- new PropertiesHandler().load(in);
- //loadingProperties = false;
- stringIDs = null;
- stringTable = null;
- }
- /////////////////////////////////////////////////////////////////////
- // methods for initializing the FontConfig //
- /////////////////////////////////////////////////////////////////////
- /**
- * set initLocale, initEncoding and initELC for this FontConfig object
- * currently we just simply use the startup locale and encoding
- */
- private void initFontConfig() {
- initLocale = startupLocale;
- initEncoding = encoding;
- if (preferLocaleFonts && !willReorderForStartupLocale()) {
- preferLocaleFonts = false;
- }
- initELC = getInitELC();
- initAllComponentFonts();
- }
- //"ELC" stands for "Encoding.Language.Country". This method returns
- //the ID of the matched elc setting of "initLocale" in elcIDs table.
- //If no match is found, it returns the default ID, which is
- //"NULL.NULL.NULL" in elcIDs table.
- private short getInitELC() {
- if (initELC != -1) {
- return initELC;
- }
- HashMap <String, Integer> elcIDs = new HashMap<String, Integer>();
- for (int i = 0; i < table_elcIDs.length; i++) {
- elcIDs.put(getString(table_elcIDs[i]), i);
- }
- String language = initLocale.getLanguage();
- String country = initLocale.getCountry();
- String elc;
- if (elcIDs.containsKey(elc=initEncoding + "." + language + "." + country)
- || elcIDs.containsKey(elc=initEncoding + "." + language)
- || elcIDs.containsKey(elc=initEncoding)) {
- initELC = elcIDs.get(elc).shortValue();
- } else {
- initELC = elcIDs.get("NULL.NULL.NULL").shortValue();
- }
- int i = 0;
- while (i < table_alphabeticSuffix.length) {
- if (initELC == table_alphabeticSuffix[i]) {
- alphabeticSuffix = getString(table_alphabeticSuffix[i + 1]);
- return initELC;
- }
- i += 2;
- }
- return initELC;
- }
- public static boolean verbose;
- private short initELC = -1;
- private Locale initLocale;
- private String initEncoding;
- private String alphabeticSuffix;
- private short[][][] compFontNameIDs = new short[NUM_FONTS][NUM_STYLES][];
- private int[][][] compExclusions = new int[NUM_FONTS][][];
- private int[] compCoreNum = new int[NUM_FONTS];
- private Set<Short> coreFontNameIDs = new HashSet<Short>();
- private Set<Short> fallbackFontNameIDs = new HashSet<Short>();
- private void initAllComponentFonts() {
- short[] fallbackScripts = getFallbackScripts();
- for (int fontIndex = 0; fontIndex < NUM_FONTS; fontIndex++) {
- short[] coreScripts = getCoreScripts(fontIndex);
- compCoreNum[fontIndex] = coreScripts.length;
- /*
- System.out.println("coreScriptID=" + table_sequences[initELC * 5 + fontIndex]);
- for (int i = 0; i < coreScripts.length; i++) {
- System.out.println(" " + i + " :" + getString(table_scriptIDs[coreScripts[i]]));
- }
- */
- //init exclusionRanges
- int[][] exclusions = new int[coreScripts.length][];
- for (int i = 0; i < coreScripts.length; i++) {
- exclusions[i] = getExclusionRanges(coreScripts[i]);
- }
- compExclusions[fontIndex] = exclusions;
- //init componentFontNames
- for (int styleIndex = 0; styleIndex < NUM_STYLES; styleIndex++) {
- int index;
- short[] nameIDs = new short[coreScripts.length + fallbackScripts.length];
- //core
- for (index = 0; index < coreScripts.length; index++) {
- nameIDs[index] = getComponentFontID(coreScripts[index],
- fontIndex, styleIndex);
- if (preferLocaleFonts && localeMap != null &&
- fontManager.usingAlternateFontforJALocales()) {
- nameIDs[index] = remapLocaleMap(fontIndex, styleIndex,
- coreScripts[index], nameIDs[index]);
- }
- if (preferPropFonts) {
- nameIDs[index] = remapProportional(fontIndex, nameIDs[index]);
- }
- //System.out.println("nameid=" + nameIDs[index]);
- coreFontNameIDs.add(nameIDs[index]);
- }
- //fallback
- for (int i = 0; i < fallbackScripts.length; i++) {
- short id = getComponentFontID(fallbackScripts[i],
- fontIndex, styleIndex);
- if (preferLocaleFonts && localeMap != null &&
- fontManager.usingAlternateFontforJALocales()) {
- id = remapLocaleMap(fontIndex, styleIndex, fallbackScripts[i], id);
- }
- if (preferPropFonts) {
- id = remapProportional(fontIndex, id);
- }
- if (contains(nameIDs, id, index)) {
- continue;
- }
- /*
- System.out.println("fontIndex=" + fontIndex + ", styleIndex=" + styleIndex
- + ", fbIndex=" + i + ",fbS=" + fallbackScripts[i] + ", id=" + id);
- */
- fallbackFontNameIDs.add(id);
- nameIDs[index++] = id;
- }
- if (index < nameIDs.length) {
- short[] newNameIDs = new short[index];
- System.arraycopy(nameIDs, 0, newNameIDs, 0, index);
- nameIDs = newNameIDs;
- }
- compFontNameIDs[fontIndex][styleIndex] = nameIDs;
- }
- }
- }
- private short remapLocaleMap(int fontIndex, int styleIndex, short scriptID, short fontID) {
- String scriptName = getString(table_scriptIDs[scriptID]);
- String value = (String)localeMap.get(scriptName);
- if (value == null) {
- String fontName = fontNames[fontIndex];
- String styleName = styleNames[styleIndex];
- value = (String)localeMap.get(fontName + "." + styleName + "." + scriptName);
- }
- if (value == null) {
- return fontID;
- }
- for (int i = 0; i < table_componentFontNameIDs.length; i++) {
- String name = getString(table_componentFontNameIDs[i]);
- if (value.equalsIgnoreCase(name)) {
- fontID = (short)i;
- break;
- }
- }
- return fontID;
- }
- public static boolean hasMonoToPropMap() {
- return table_proportionals != null && table_proportionals.length != 0;
- }
- private short remapProportional(int fontIndex, short id) {
- if (preferPropFonts &&
- table_proportionals.length != 0 &&
- fontIndex != 2 && //"monospaced"
- fontIndex != 4) { //"dialoginput"
- int i = 0;
- while (i < table_proportionals.length) {
- if (table_proportionals[i] == id) {
- return table_proportionals[i + 1];
- }
- i += 2;
- }
- }
- return id;
- }
- /////////////////////////////////////////////////////////////////////
- // Methods for handling font and style names //
- /////////////////////////////////////////////////////////////////////
- protected static final int NUM_FONTS = 5;
- protected static final int NUM_STYLES = 4;
- protected static final String[] fontNames
- = {"serif", "sansserif", "monospaced", "dialog", "dialoginput"};
- protected static final String[] publicFontNames
- = {Font.SERIF, Font.SANS_SERIF, Font.MONOSPACED, Font.DIALOG,
- Font.DIALOG_INPUT};
- protected static final String[] styleNames
- = {"plain", "bold", "italic", "bolditalic"};
- /**
- * Checks whether the given font family name is a valid logical font name.
- * The check is case insensitive.
- */
- public static boolean isLogicalFontFamilyName(String fontName) {
- return isLogicalFontFamilyNameLC(fontName.toLowerCase(Locale.ENGLISH));
- }
- /**
- * Checks whether the given font family name is a valid logical font name.
- * The check is case sensitive.
- */
- public static boolean isLogicalFontFamilyNameLC(String fontName) {
- for (int i = 0; i < fontNames.length; i++) {
- if (fontName.equals(fontNames[i])) {
- return true;
- }
- }
- return false;
- }
- /**
- * Checks whether the given style name is a valid logical font style name.
- */
- private static boolean isLogicalFontStyleName(String styleName) {
- for (int i = 0; i < styleNames.length; i++) {
- if (styleName.equals(styleNames[i])) {
- return true;
- }
- }
- return false;
- }
- /**
- * Checks whether the given font face name is a valid logical font name.
- * The check is case insensitive.
- */
- public static boolean isLogicalFontFaceName(String fontName) {
- return isLogicalFontFaceNameLC(fontName.toLowerCase(Locale.ENGLISH));
- }
- /**
- * Checks whether the given font face name is a valid logical font name.
- * The check is case sensitive.
- */
- public static boolean isLogicalFontFaceNameLC(String fontName) {
- int period = fontName.indexOf('.');
- if (period >= 0) {
- String familyName = fontName.substring(0, period);
- String styleName = fontName.substring(period + 1);
- return isLogicalFontFamilyName(familyName) &&
- isLogicalFontStyleName(styleName);
- } else {
- return isLogicalFontFamilyName(fontName);
- }
- }
- protected static int getFontIndex(String fontName) {
- return getArrayIndex(fontNames, fontName);
- }
- protected static int getStyleIndex(String styleName) {
- return getArrayIndex(styleNames, styleName);
- }
- private static int getArrayIndex(String[] names, String name) {
- for (int i = 0; i < names.length; i++) {
- if (name.equals(names[i])) {
- return i;
- }
- }
- assert false;
- return 0;
- }
- protected static int getStyleIndex(int style) {
- switch (style) {
- case Font.PLAIN:
- return 0;
- case Font.BOLD:
- return 1;
- case Font.ITALIC:
- return 2;
- case Font.BOLD | Font.ITALIC:
- return 3;
- default:
- return 0;
- }
- }
- protected static String getFontName(int fontIndex) {
- return fontNames[fontIndex];
- }
- protected static String getStyleName(int styleIndex) {
- return styleNames[styleIndex];
- }
- /**
- * Returns the font face name for the given logical font
- * family name and style.
- * The style argument is interpreted as in java.awt.Font.Font.
- */
- public static String getLogicalFontFaceName(String familyName, int style) {
- assert isLogicalFontFamilyName(familyName);
- return familyName.toLowerCase(Locale.ENGLISH) + "." + getStyleString(style);
- }
- /**
- * Returns the string typically used in properties files
- * for the given style.
- * The style argument is interpreted as in java.awt.Font.Font.
- */
- public static String getStyleString(int style) {
- return getStyleName(getStyleIndex(style));
- }
- /**
- * Returns a fallback name for the given font name. For a few known
- * font names, matching logical font names are returned. For all
- * other font names, defaultFallback is returned.
- * defaultFallback differs between AWT and 2D.
- */
- public abstract String getFallbackFamilyName(String fontName, String defaultFallback);
- /**
- * Returns the 1.1 equivalent for some old 1.0 font family names for
- * which we need to maintain compatibility in some configurations.
- * Returns null for other font names.
- */
- protected String getCompatibilityFamilyName(String fontName) {
- fontName = fontName.toLowerCase(Locale.ENGLISH);
- if (fontName.equals("timesroman")) {
- return "serif";
- } else if (fontName.equals("helvetica")) {
- return "sansserif";
- } else if (fontName.equals("courier")) {
- return "monospaced";
- }
- return null;
- }
- protected static String[] installedFallbackFontFiles = null;
- /**
- * Maps a file name given in the font configuration file
- * to a format appropriate for the platform.
- */
- protected String mapFileName(String fileName) {
- return fileName;
- }
- //////////////////////////////////////////////////////////////////////
- // reordering //
- //////////////////////////////////////////////////////////////////////
- /* Mappings from file encoding to font config name for font supporting
- * the corresponding language. This is filled in by initReorderMap()
- */
- protected HashMap reorderMap = null;
- /* Platform-specific mappings */
- protected abstract void initReorderMap();
- /* Move item at index "src" to "dst", shuffling all values in
- * between down
- */
- private void shuffle(String[] seq, int src, int dst) {
- if (dst >= src) {
- return;
- }
- String tmp = seq[src];
- for (int i=src; i>dst; i--) {
- seq[i] = seq[i-1];
- }
- seq[dst] = tmp;
- }
- /* Called to determine if there's a re-order sequence for this locale/
- * encoding. If there's none then the caller can "bail" and avoid
- * unnecessary work
- */
- public static boolean willReorderForStartupLocale() {
- return getReorderSequence() != null;
- }
- private static Object getReorderSequence() {
- if (fontConfig.reorderMap == null) {
- fontConfig.initReorderMap();
- }
- HashMap reorderMap = fontConfig.reorderMap;
- /* Find the most specific mapping */
- String language = startupLocale.getLanguage();
- String country = startupLocale.getCountry();
- Object val = reorderMap.get(encoding + "." + language + "." + country);
- if (val == null) {
- val = reorderMap.get(encoding + "." + language);
- }
- if (val == null) {
- val = reorderMap.get(encoding);
- }
- return val;
- }
- /* This method reorders the sequence such that the matches for the
- * file encoding are moved ahead of other elements.
- * If an encoding uses more than one font, they are all moved up.
- */
- private void reorderSequenceForLocale(String[] seq) {
- Object val = getReorderSequence();
- if (val instanceof String) {
- for (int i=0; i< seq.length; i++) {
- if (seq[i].equals(val)) {
- shuffle(seq, i, 0);
- return;
- }
- }
- } else if (val instanceof String[]) {
- String[] fontLangs = (String[])val;
- for (int l=0; l<fontLangs.length;l++) {
- for (int i=0; i<seq.length;i++) {
- if (seq[i].equals(fontLangs[l])) {
- shuffle(seq, i, l);
- }
- }
- }
- }
- }
- private static Vector splitSequence(String sequence) {
- //String.split would be more convenient, but incurs big performance penalty
- Vector parts = new Vector();
- int start = 0;
- int end;
- while ((end = sequence.indexOf(',', start)) >= 0) {
- parts.add(sequence.substring(start, end));
- start = end + 1;
- }
- if (sequence.length() > start) {
- parts.add(sequence.substring(start, sequence.length()));
- }
- return parts;
- }
- protected String[] split(String sequence) {
- Vector v = splitSequence(sequence);
- return (String[])v.toArray(new String[0]);
- }
- ////////////////////////////////////////////////////////////////////////
- // Methods for extracting information from the fontconfig data for AWT//
- ////////////////////////////////////////////////////////////////////////
- private Hashtable charsetRegistry = new Hashtable(5);
- /**
- * Returns FontDescriptors describing the physical fonts used for the
- * given logical font name and style. The font name is interpreted
- * in a case insensitive way.
- * The style argument is interpreted as in java.awt.Font.Font.
- */
- public FontDescriptor[] getFontDescriptors(String fontName, int style) {
- assert isLogicalFontFamilyName(fontName);
- fontName = fontName.toLowerCase(Locale.ENGLISH);
- int fontIndex = getFontIndex(fontName);
- int styleIndex = getStyleIndex(style);
- return getFontDescriptors(fontIndex, styleIndex);
- }
- private FontDescriptor[][][] fontDescriptors =
- new FontDescriptor[NUM_FONTS][NUM_STYLES][];
- private FontDescriptor[] getFontDescriptors(int fontIndex, int styleIndex) {
- FontDescriptor[] descriptors = fontDescriptors[fontIndex][styleIndex];
- if (descriptors == null) {
- descriptors = buildFontDescriptors(fontIndex, styleIndex);
- fontDescriptors[fontIndex][styleIndex] = descriptors;
- }
- return descriptors;
- }
- private FontDescriptor[] buildFontDescriptors(int fontIndex, int styleIndex) {
- String fontName = fontNames[fontIndex];
- String styleName = styleNames[styleIndex];
- short[] scriptIDs = getCoreScripts(fontIndex);
- short[] nameIDs = compFontNameIDs[fontIndex][styleIndex];
- String[] sequence = new String[scriptIDs.length];
- String[] names = new String[scriptIDs.length];
- for (int i = 0; i < sequence.length; i++) {
- names[i] = getComponentFontName(nameIDs[i]);
- sequence[i] = getScriptName(scriptIDs[i]);
- if (alphabeticSuffix != null && "alphabetic".equals(sequence[i])) {
- sequence[i] = sequence[i] + "/" + alphabeticSuffix;
- }
- }
- int[][] fontExclusionRanges = compExclusions[fontIndex];
- FontDescriptor[] descriptors = new FontDescriptor[names.length];
- for (int i = 0; i < names.length; i++) {
- String awtFontName;
- String encoding;
- awtFontName = makeAWTFontName(names[i], sequence[i]);
- // look up character encoding
- encoding = getEncoding(names[i], sequence[i]);
- if (encoding == null) {
- encoding = "default";
- }
- CharsetEncoder enc
- = getFontCharsetEncoder(encoding.trim(), awtFontName);
- // we already have the exclusion ranges
- int[] exclusionRanges = fontExclusionRanges[i];
- // create descriptor
- descriptors[i] = new FontDescriptor(awtFontName, enc, exclusionRanges);
- }
- return descriptors;
- }
- /**
- * Returns the AWT font name for the given platform font name and
- * character subset.
- */
- protected String makeAWTFontName(String platformFontName,
- String characterSubsetName) {
- return platformFontName;
- }
- /**
- * Returns the java.io name of the platform character encoding for the
- * given AWT font name and character subset. May return "default"
- * to indicate that getDefaultFontCharset should be called to obtain
- * a charset encoder.
- */
- protected abstract String getEncoding(String awtFontName,
- String characterSubsetName);
- private CharsetEncoder getFontCharsetEncoder(final String charsetName,
- String fontName) {
- Charset fc = null;
- if (charsetName.equals("default")) {
- fc = (Charset) charsetRegistry.get(fontName);
- } else {
- fc = (Charset) charsetRegistry.get(charsetName);
- }
- if (fc != null) {
- return fc.newEncoder();
- }
- if (!charsetName.startsWith("sun.awt.") && !charsetName.equals("default")) {
- fc = Charset.forName(charsetName);
- } else {
- Class fcc = (Class) AccessController.doPrivileged(new PrivilegedAction() {
- public Object run() {
- try {
- return Class.forName(charsetName, true,
- ClassLoader.getSystemClassLoader());
- } catch (ClassNotFoundException e) {
- }
- return null;
- }
- });
- if (fcc != null) {
- try {
- fc = (Charset) fcc.newInstance();
- } catch (Exception e) {
- }
- }
- }
- if (fc == null) {
- fc = getDefaultFontCharset(fontName);
- }
- if (charsetName.equals("default")){
- charsetRegistry.put(fontName, fc);
- } else {
- charsetRegistry.put(charsetName, fc);
- }
- return fc.newEncoder();
- }
- protected abstract Charset getDefaultFontCharset(
- String fontName);
- /* This retrieves the platform font directories (path) calculated
- * by setAWTFontPathSequence(String[]). The default implementation
- * returns null, its expected that X11 platforms may return
- * non-null.
- */
- public HashSet<String> getAWTFontPathSet() {
- return null;
- }
- ////////////////////////////////////////////////////////////////////////
- // methods for extracting information from the fontconfig data for 2D //
- ////////////////////////////////////////////////////////////////////////
- /**
- * Returns an array of composite font descriptors for all logical font
- * faces.
- * If the font configuration file doesn't specify Lucida Sans Regular
- * or the given fallback font as component fonts, they are added here.
- */
- public CompositeFontDescriptor[] get2DCompositeFontInfo() {
- CompositeFontDescriptor[] result =
- new CompositeFontDescriptor[NUM_FONTS * NUM_STYLES];
- String defaultFontFile = fontManager.getDefaultFontFile();
- String defaultFontFaceName = fontManager.getDefaultFontFaceName();
- for (int fontIndex = 0; fontIndex < NUM_FONTS; fontIndex++) {
- String fontName = publicFontNames[fontIndex];
- // determine exclusion ranges for font
- // AWT uses separate exclusion range array per component font.
- // 2D packs all range boundaries into one array.
- // Both use separate entries for lower and upper boundary.
- int[][] exclusions = compExclusions[fontIndex];
- int numExclusionRanges = 0;
- for (int i = 0; i < exclusions.length; i++) {
- numExclusionRanges += exclusions[i].length;
- }
- int[] exclusionRanges = new int[numExclusionRanges];
- int[] exclusionRangeLimits = new int[exclusions.length];
- int exclusionRangeIndex = 0;
- int exclusionRangeLimitIndex = 0;
- for (int i = 0; i < exclusions.length; i++) {
- int[] componentRanges = exclusions[i];
- for (int j = 0; j < componentRanges.length; ) {
- int value = componentRanges[j];
- exclusionRanges[exclusionRangeIndex++] = componentRanges[j++];
- exclusionRanges[exclusionRangeIndex++] = componentRanges[j++];
- }
- exclusionRangeLimits[i] = exclusionRangeIndex;
- }
- // other info is per style
- for (int styleIndex = 0; styleIndex < NUM_STYLES; styleIndex++) {
- int maxComponentFontCount = compFontNameIDs[fontIndex][styleIndex].length;
- boolean sawDefaultFontFile = false;
- // fall back fonts listed in the lib/fonts/fallback directory
- if (installedFallbackFontFiles != null) {
- maxComponentFontCount += installedFallbackFontFiles.length;
- }
- String faceName = fontName + "." + styleNames[styleIndex];
- // determine face names and file names of component fonts
- String[] componentFaceNames = new String[maxComponentFontCount];
- String[] componentFileNames = new String[maxComponentFontCount];
- int index;
- for (index = 0; index < compFontNameIDs[fontIndex][styleIndex].length; index++) {
- short fontNameID = compFontNameIDs[fontIndex][styleIndex][index];
- short fileNameID = getComponentFileID(fontNameID);
- componentFaceNames[index] = getFaceNameFromComponentFontName(getComponentFontName(fontNameID));
- componentFileNames[index] = mapFileName(getComponentFileName(fileNameID));
- if (componentFileNames[index] == null ||
- needToSearchForFile(componentFileNames[index])) {
- componentFileNames[index] = getFileNameFromComponentFontName(getComponentFontName(fontNameID));
- }
- if (!sawDefaultFontFile &&
- defaultFontFile.equals(componentFileNames[index])) {
- sawDefaultFontFile = true;
- }
- /*
- System.out.println(publicFontNames[fontIndex] + "." + styleNames[styleIndex] + "."
- + getString(table_scriptIDs[coreScripts[index]]) + "=" + componentFileNames[index]);
- */
- }
- //"Lucida Sans Regular" is not in the list, we add it here
- if (!sawDefaultFontFile) {
- int len = 0;
- if (installedFallbackFontFiles != null) {
- len = installedFallbackFontFiles.length;
- }
- if (index + len == maxComponentFontCount) {
- String[] newComponentFaceNames = new String[maxComponentFontCount + 1];
- System.arraycopy(componentFaceNames, 0, newComponentFaceNames, 0, index);
- componentFaceNames = newComponentFaceNames;
- String[] newComponentFileNames = new String[maxComponentFontCount + 1];
- System.arraycopy(componentFileNames, 0, newComponentFileNames, 0, index);
- componentFileNames = newComponentFileNames;
- }
- componentFaceNames[index] = defaultFontFaceName;
- componentFileNames[index] = defaultFontFile;
- index++;
- }
- if (installedFallbackFontFiles != null) {
- for (int ifb=0; ifb<installedFallbackFontFiles.length; ifb++) {
- componentFaceNames[index] = null;
- componentFileNames[index] = installedFallbackFontFiles[ifb];
- index++;
- }
- }
- if (index < maxComponentFontCount) {
- String[] newComponentFaceNames = new String[index];
- System.arraycopy(componentFaceNames, 0, newComponentFaceNames, 0, index);
- componentFaceNames = newComponentFaceNames;
- String[] newComponentFileNames = new String[index];
- System.arraycopy(componentFileNames, 0, newComponentFileNames, 0, index);
- componentFileNames = newComponentFileNames;
- }
- // exclusion range limit array length must match component face name
- // array length - native code relies on this
- int[] clippedExclusionRangeLimits = exclusionRangeLimits;
- if (index != clippedExclusionRangeLimits.length) {
- int len = exclusionRangeLimits.length;
- clippedExclusionRangeLimits = new int[index];
- System.arraycopy(exclusionRangeLimits, 0, clippedExclusionRangeLimits, 0, len);
- //padding for various fallback fonts
- for (int i = len; i < index; i++) {
- clippedExclusionRangeLimits[i] = exclusionRanges.length;
- }
- }
- /*
- System.out.println(faceName + ":");
- for (int i = 0; i < componentFileNames.length; i++) {
- System.out.println(" " + componentFaceNames[i]
- + " -> " + componentFileNames[i]);
- }
- */
- result[fontIndex * NUM_STYLES + styleIndex]
- = new CompositeFontDescriptor(
- faceName,
- compCoreNum[fontIndex],
- componentFaceNames,
- componentFileNames,
- exclusionRanges,
- clippedExclusionRangeLimits);
- }
- }
- return result;
- }
- protected abstract String getFaceNameFromComponentFontName(String componentFontName);
- protected abstract String getFileNameFromComponentFontName(String componentFontName);
- /*
- public class 2dFont {
- public String platformName;
- public String fontfileName;
- }
- private 2dFont [] componentFonts = null;
- */
- /* Used on Linux to test if a file referenced in a font configuration
- * file exists in the location that is expected. If it does, no need
- * to search for it. If it doesn't then unless its a fallback font,
- * return that expensive code should be invoked to search for the font.
- */
- HashMap<String, Boolean> existsMap;
- public boolean needToSearchForFile(String fileName) {
- if (!FontUtilities.isLinux) {
- return false;
- } else if (existsMap == null) {
- existsMap = new HashMap<String, Boolean>();
- }
- Boolean exists = existsMap.get(fileName);
- if (exists == null) {
- /* call getNumberCoreFonts() to ensure these are initialised, and
- * if this file isn't for a core component, ie, is a for a fallback
- * font which very typically isn't available, then can't afford
- * to take the start-up penalty to search for it.
- */
- getNumberCoreFonts();
- if (!coreFontFileNames.contains(fileName)) {
- exists = Boolean.TRUE;
- } else {
- exists = Boolean.valueOf((new File(fileName)).exists());
- existsMap.put(fileName, exists);
- if (FontUtilities.debugFonts() &&
- exists == Boolean.FALSE) {
- logger.warning("Couldn't locate font file " + fileName);
- }
- }
- }
- return exists == Boolean.FALSE;
- }
- private int numCoreFonts = -1;
- private String[] componentFonts = null;
- HashMap <String, String> filenamesMap = new HashMap<String, String>();
- HashSet <String> coreFontFileNames = new HashSet<String>();
- /* Return the number of core fonts. Note this isn't thread safe but
- * a calling thread can call this and getPlatformFontNames() in either
- * order.
- */
- public int getNumberCoreFonts() {
- if (numCoreFonts == -1) {
- numCoreFonts = coreFontNameIDs.size();
- Short[] emptyShortArray = new Short[0];
- Short[] core = coreFontNameIDs.toArray(emptyShortArray);
- Short[] fallback = fallbackFontNameIDs.toArray(emptyShortArray);
- int numFallbackFonts = 0;
- int i;
- for (i = 0; i < fallback.length; i++) {
- if (coreFontNameIDs.contains(fallback[i])) {
- fallback[i] = null;
- continue;
- }
- numFallbackFonts++;
- }
- componentFonts = new String[numCoreFonts + numFallbackFonts];
- String filename = null;
- for (i = 0; i < core.length; i++) {
- short fontid = core[i];
- short fileid = getComponentFileID(fontid);
- componentFonts[i] = getComponentFontName(fontid);
- String compFileName = getComponentFileName(fileid);
- if (compFileName != null) {
- coreFontFileNames.add(compFileName);
- }
- filenamesMap.put(componentFonts[i], mapFileName(compFileName));
- }
- for (int j = 0; j < fallback.length; j++) {
- if (fallback[j] != null) {
- short fontid = fallback[j];
- short fileid = getComponentFileID(fontid);
- componentFonts[i] = getComponentFontName(fontid);
- filenamesMap.put(componentFonts[i],
- mapFileName(getComponentFileName(fileid)));
- i++;
- }
- }
- }
- return numCoreFonts;
- }
- /* Return all platform font names used by this font configuration.
- * The first getNumberCoreFonts() entries are guaranteed to be the
- * core fonts - ie no fall back only fonts.
- */
- public String[] getPlatformFontNames() {
- if (numCoreFonts == -1) {
- getNumberCoreFonts();
- }
- return componentFonts;
- }
- /**
- * Returns a file name for the physical font represented by this platform font name,
- * if the font configuration has such information available, or null if the
- * information is unavailable. The file name returned is just a hint; a null return
- * value doesn't necessarily mean that the font is unavailable, nor does a non-null
- * return value guarantee that the file exists and contains the physical font.
- * The file name can be an absolute or a relative path name.
- */
- public String getFileNameFromPlatformName(String platformName) {
- // get2DCompositeFontInfo
- // -> getFileNameFromComponentfontName() (W/M)
- // -> getFileNameFromPlatformName()
- // it's a waste of time on Win32, but I have to give X11 a chance to
- // call getFileNameFromXLFD()
- return filenamesMap.get(platformName);
- }
- /**
- * Returns a configuration specific path to be appended to the font
- * search path.
- */
- public String getExtraFontPath() {
- return getString(head[INDEX_appendedfontpath]);
- }
- public String getVersion() {
- return getString(head[INDEX_version]);
- }
- /* subclass support */
- protected static FontConfiguration getFontConfiguration() {
- return fontConfig;
- }
- protected void setFontConfiguration() {
- fontConfig = this; /* static initialization */
- }
- //////////////////////////////////////////////////////////////////////
- // FontConfig data tables and the index constants in binary file //
- //////////////////////////////////////////////////////////////////////
- /* The binary font configuration file begins with a short[] "head", which
- * contains the offsets to the starts of the individual data table which
- * immediately follow. Teh current implemention includes the tables shown
- * below.
- *
- * (00) table_scriptIDs :stringIDs of all defined CharacterSubsetNames
- * (01) table_scriptFonts :scriptID x fontIndex x styleIndex->
- * PlatformFontNameID mapping. Each scriptID might
- * have 1 or 20 entries depends on if it is defined
- * via a "allfonts.CharacterSubsetname" or a list of
- * "LogicalFontName.StyleName.CharacterSubsetName"
- * entries, positive entry means it's a "allfonts"
- * entry, a negative value means this is a offset to
- * a NUM_FONTS x NUM_STYLES subtable.
- * (02) table_elcIDs :stringIDs of all defined ELC names, string
- * "NULL.NULL.NULL" is used for "default"
- * (03) table_sequences :elcID x logicalFont -> scriptIDs table defined
- * by "sequence.allfonts/LogicalFontName.ELC" in
- * font configuration file, each "elcID" has
- * NUM_FONTS (5) entries in this table.
- * (04) table_fontfileNameIDs
- * :stringIDs of all defined font file names
- * (05) table_componentFontNameIDs
- * :stringIDs of all defined PlatformFontNames
- * (06) table_filenames :platformFontNamesID->fontfileNameID mapping
- * table, the index is the platformFontNamesID.
- * (07) table_awtfontpaths :CharacterSubsetNames->awtfontpaths mapping table,
- * the index is the CharacterSubsetName's stringID
- * and content is the stringID of awtfontpath.
- * (08) table_exclusions :scriptID -> exclusionRanges mapping table,
- * the index is the scriptID and the content is
- a id of an exclusionRanges int[].
- * (09) table_proportionals:list of pairs of PlatformFontNameIDs, stores
- * the replacement info defined by "proportional"
- * keyword.
- * (10) table_scriptFontsMotif
- * :same as (01) except this table stores the
- * info defined with ".motif" keyword
- * (11) table_alphabeticSuffix
- * :elcID -> stringID of alphabetic/XXXX entries
- * (12) table_stringIDs :The index of this table is the string ID, the
- * content is the "start index" of this string in
- * stringTable, use the start index of next entry
- * as the "end index".
- * (13) table_stringTable :The real storage of all character strings defined
- * /used this font configuration, need a pair of
- * "start" and "end" indices to access.
- * (14) reserved
- * (15) table_fallbackScripts
- * :stringIDs of fallback CharacterSubsetnames, stored
- * in the order of they are defined in sequence.fallback.
- * (16) table_appendedfontpath
- * :stringtID of the "appendedfontpath" defined.
- * (17) table_version :stringID of the version number of this fontconfig file.
- */
- private static final int HEAD_LENGTH = 20;
- private static final int INDEX_scriptIDs = 0;
- private static final int INDEX_scriptFonts = 1;
- private static final int INDEX_elcIDs = 2;
- private static final int INDEX_sequences = 3;
- private static final int INDEX_fontfileNameIDs = 4;
- private static final int INDEX_componentFontNameIDs = 5;
- private static final int INDEX_filenames = 6;
- private static final int INDEX_awtfontpaths = 7;
- private static final int INDEX_exclusions = 8;
- private static final int INDEX_proportionals = 9;
- private static final int INDEX_scriptFontsMotif = 10;
- private static final int INDEX_alphabeticSuffix = 11;
- private static final int INDEX_stringIDs = 12;
- private static final int INDEX_stringTable = 13;
- private static final int INDEX_TABLEEND = 14;
- private static final int INDEX_fallbackScripts = 15;
- private static final int INDEX_appendedfontpath = 16;
- private static final int INDEX_version = 17;
- private static short[] head;
- private static short[] table_scriptIDs;
- private static short[] table_scriptFonts;
- private static short[] table_elcIDs;
- private static short[] table_sequences;
- private static short[] table_fontfileNameIDs;
- private static short[] table_componentFontNameIDs;
- private static short[] table_filenames;
- protected static short[] table_awtfontpaths;
- private static short[] table_exclusions;
- private static short[] table_proportionals;
- private static short[] table_scriptFontsMotif;
- private static short[] table_alphabeticSuffix;
- private static short[] table_stringIDs;
- private static char[] table_stringTable;
- /**
- * Checks consistencies of complied fontconfig data. This method
- * is called only at the build-time from
- * build.tools.compilefontconfig.CompileFontConfig.
- */
- private static void sanityCheck() {
- int errors = 0;
- //This method will only be called during build time, do we
- //need do PrivilegedAction?
- String osName = (String)java.security.AccessController.doPrivileged(
- new java.security.PrivilegedAction() {
- public Object run() {
- return System.getProperty("os.name");
- }
- });
- //componentFontNameID starts from "1"
- for (int ii = 1; ii < table_filenames.length; ii++) {
- if (table_filenames[ii] == -1) {
- // The corresponding finename entry for a component
- // font name is mandatory on Windows, but it's
- // optional on Solaris and Linux.
- if (osName.contains("Windows")) {
- System.err.println("\n Error: <filename."
- + getString(table_componentFontNameIDs[ii])
- + "> entry is missing!!!");
- errors++;
- } else {
- if (verbose && !isEmpty(table_filenames)) {
- System.err.println("\n Note: 'filename' entry is undefined for \""
- + getString(table_componentFontNameIDs[ii])
- + "\"");
- }
- }
- }
- }
- for (int ii = 0; ii < table_scriptIDs.length; ii++) {
- short fid = table_scriptFonts[ii];
- if (fid == 0) {
- System.out.println("\n Error: <allfonts."
- + getString(table_scriptIDs[ii])
- + "> entry is missing!!!");
- errors++;
- continue;
- } else if (fid < 0) {
- fid = (short)-fid;
- for (int iii = 0; iii < NUM_FONTS; iii++) {
- for (int iij = 0; iij < NUM_STYLES; iij++) {
- int jj = iii * NUM_STYLES + iij;
- short ffid = table_scriptFonts[fid + jj];
- if (ffid == 0) {
- System.err.println("\n Error: <"
- + getFontName(iii) + "."
- + getStyleName(iij) + "."
- + getString(table_scriptIDs[ii])
- + "> entry is missing!!!");
- errors++;
- }
- }
- }
- }
- }
- if ("SunOS".equals(osName)) {
- for (int ii = 0; ii < table_awtfontpaths.length; ii++) {
- if (table_awtfontpaths[ii] == 0) {
- String script = getString(table_scriptIDs[ii]);
- if (script.contains("lucida") ||
- script.contains("dingbats") ||
- script.contains("symbol")) {
- continue;
- }
- System.err.println("\nError: "
- + "<awtfontpath."
- + script
- + "> entry is missing!!!");
- errors++;
- }
- }
- }
- if (errors != 0) {
- System.err.println("!!THERE ARE " + errors + " ERROR(S) IN "
- + "THE FONTCONFIG FILE, PLEASE CHECK ITS CONTENT!!\n");
- System.exit(1);
- }
- }
- private static boolean isEmpty(short[] a) {
- for (short s : a) {
- if (s != -1) {
- return false;
- }
- }
- return true;
- }
- //dump the fontconfig data tables
- private static void dump() {
- System.out.println("\n----Head Table------------");
- for (int ii = 0; ii < HEAD_LENGTH; ii++) {
- System.out.println(" " + ii + " : " + head[ii]);
- }
- System.out.println("\n----scriptIDs-------------");
- printTable(table_scriptIDs, 0);
- System.out.println("\n----scriptFonts----------------");
- for (int ii = 0; ii < table_scriptIDs.length; ii++) {
- short fid = table_scriptFonts[ii];
- if (fid >= 0) {
- System.out.println(" allfonts."
- + getString(table_scriptIDs[ii])
- + "="
- + getString(table_componentFontNameIDs[fid]));
- }
- }
- for (int ii = 0; ii < table_scriptIDs.length; ii++) {
- short fid = table_scriptFonts[ii];
- if (fid < 0) {
- fid = (short)-fid;
- for (int iii = 0; iii < NUM_FONTS; iii++) {
- for (int iij = 0; iij < NUM_STYLES; iij++) {
- int jj = iii * NUM_STYLES + iij;
- short ffid = table_scriptFonts[fid + jj];
- System.out.println(" "
- + getFontName(iii) + "."
- + getStyleName(iij) + "."
- + getString(table_scriptIDs[ii])
- + "="
- + getString(table_componentFontNameIDs[ffid]));
- }
- }
- }
- }
- System.out.println("\n----elcIDs----------------");
- printTable(table_elcIDs, 0);
- System.out.println("\n----sequences-------------");
- for (int ii = 0; ii< table_elcIDs.length; ii++) {
- System.out.println(" " + ii + "/" + getString((short)table_elcIDs[ii]));
- short[] ss = getShortArray(table_sequences[ii * NUM_FONTS + 0]);
- for (int jj = 0; jj < ss.length; jj++) {
- System.out.println(" " + getString((short)table_scriptIDs[ss[jj]]));
- }
- }
- System.out.println("\n----fontfileNameIDs-------");
- printTable(table_fontfileNameIDs, 0);
- System.out.println("\n----componentFontNameIDs--");
- printTable(table_componentFontNameIDs, 1);
- System.out.println("\n----filenames-------------");
- for (int ii = 0; ii < table_filenames.length; ii++) {
- if (table_filenames[ii] == -1) {
- System.out.println(" " + ii + " : null");
- } else {
- System.out.println(" " + ii + " : "
- + getString(table_fontfileNameIDs[table_filenames[ii]]));
- }
- }
- System.out.println("\n----awtfontpaths---------");
- for (int ii = 0; ii < table_awtfontpaths.length; ii++) {
- System.out.println(" " + getString(table_scriptIDs[ii])
- + " : "
- + getString(table_awtfontpaths[ii]));
- }
- System.out.println("\n----proportionals--------");
- for (int ii = 0; ii < table_proportionals.length; ii++) {
- System.out.println(" "
- + getString((short)table_componentFontNameIDs[table_proportionals[ii++]])
- + " -> "
- + getString((short)table_componentFontNameIDs[table_proportionals[ii]]));
- }
- int i = 0;
- System.out.println("\n----alphabeticSuffix----");
- while (i < table_alphabeticSuffix.length) {
- System.out.println(" " + getString(table_elcIDs[table_alphabeticSuffix[i++]])
- + " -> " + getString(table_alphabeticSuffix[i++]));
- }
- System.out.println("\n----String Table---------");
- System.out.println(" stringID: Num =" + table_stringIDs.length);
- System.out.println(" stringTable: Size=" + table_stringTable.length * 2);
- System.out.println("\n----fallbackScriptIDs---");
- short[] fbsIDs = getShortArray(head[INDEX_fallbackScripts]);
- for (int ii = 0; ii < fbsIDs.length; ii++) {
- System.out.println(" " + getString(table_scriptIDs[fbsIDs[ii]]));
- }
- System.out.println("\n----appendedfontpath-----");
- System.out.println(" " + getString(head[INDEX_appendedfontpath]));
- System.out.println("\n----Version--------------");
- System.out.println(" " + getString(head[INDEX_version]));
- }
- //////////////////////////////////////////////////////////////////////
- // Data table access methods //
- //////////////////////////////////////////////////////////////////////
- /* Return the fontID of the platformFontName defined in this font config
- * by "LogicalFontName.StyleName.CharacterSubsetName" entry or
- * "allfonts.CharacterSubsetName" entry in properties format fc file.
- */
- protected static short getComponentFontID(short scriptID, int fontIndex, int styleIndex) {
- short fid = table_scriptFonts[scriptID];
- //System.out.println("fid=" + fid + "/ scriptID=" + scriptID + ", fi=" + fontIndex + ", si=" + styleIndex);
- if (fid >= 0) {
- //"allfonts"
- return fid;
- } else {
- return table_scriptFonts[-fid + fontIndex * NUM_STYLES + styleIndex];
- }
- }
- /* Same as getCompoentFontID() except this method returns the fontID define by
- * "xxxx.motif" entry.
- */
- protected static short getComponentFontIDMotif(short scriptID, int fontIndex, int styleIndex) {
- if (table_scriptFontsMotif.length == 0) {
- return 0;
- }
- short fid = table_scriptFontsMotif[scriptID];
- if (fid >= 0) {
- //"allfonts" > 0 or "not defined" == 0
- return fid;
- } else {
- return table_scriptFontsMotif[-fid + fontIndex * NUM_STYLES + styleIndex];
- }
- }
- private static int[] getExclusionRanges(short scriptID) {
- short exID = table_exclusions[scriptID];
- if (exID == 0) {
- return EMPTY_INT_ARRAY;
- } else {
- char[] exChar = getString(exID).toCharArray();
- int[] exInt = new int[exChar.length / 2];
- int i = 0;
- for (int j = 0; j < exInt.length; j++) {
- exInt[j] = (exChar[i++] << 16) + (exChar[i++] & 0xffff);
- }
- return exInt;
- }
- }
- private static boolean contains(short IDs[], short id, int limit) {
- for (int i = 0; i < limit; i++) {
- if (IDs[i] == id) {
- return true;
- }
- }
- return false;
- }
- /* Return the PlatformFontName from its fontID*/
- protected static String getComponentFontName(short id) {
- if (id < 0) {
- return null;
- }
- return getString(table_componentFontNameIDs[id]);
- }
- private static String getComponentFileName(short id) {
- if (id < 0) {
- return null;
- }
- return getString(table_fontfileNameIDs[id]);
- }
- //componentFontID -> componentFileID
- private static short getComponentFileID(short nameID) {
- return table_filenames[nameID];
- }
- private static String getScriptName(short scriptID) {
- return getString(table_scriptIDs[scriptID]);
- }
- private HashMap<String, Short> reorderScripts;
- protected short[] getCoreScripts(int fontIndex) {
- short elc = getInitELC();
- /*
- System.out.println("getCoreScripts: elc=" + elc + ", fontIndex=" + fontIndex);
- short[] ss = getShortArray(table_sequences[elc * NUM_FONTS + fontIndex]);
- for (int i = 0; i < ss.length; i++) {
- System.out.println(" " + getString((short)table_scriptIDs[ss[i]]));
- }
- */
- short[] scripts = getShortArray(table_sequences[elc * NUM_FONTS + fontIndex]);
- if (preferLocaleFonts) {
- if (reorderScripts == null) {
- reorderScripts = new HashMap<String, Short>();
- }
- String[] ss = new String[scripts.length];
- for (int i = 0; i < ss.length; i++) {
- ss[i] = getScriptName(scripts[i]);
- reorderScripts.put(ss[i], scripts[i]);
- }
- reorderSequenceForLocale(ss);
- for (int i = 0; i < ss.length; i++) {
- scripts[i] = reorderScripts.get(ss[i]);
- }
- }
- return scripts;
- }
- private static short[] getFallbackScripts() {
- return getShortArray(head[INDEX_fallbackScripts]);
- }
- private static void printTable(short[] list, int start) {
- for (int i = start; i < list.length; i++) {
- System.out.println(" " + i + " : " + getString(list[i]));
- }
- }
- private static short[] readShortTable(DataInputStream in, int len )
- throws IOException {
- if (len == 0) {
- return EMPTY_SHORT_ARRAY;
- }
- short[] data = new short[len];
- byte[] bb = new byte[len * 2];
- in.read(bb);
- int i = 0,j = 0;
- while (i < len) {
- data[i++] = (short)(bb[j++] << 8 | (bb[j++] & 0xff));
- }
- return data;
- }
- private static void writeShortTable(DataOutputStream out, short[] data)
- throws IOException {
- for (short val : data) {
- out.writeShort(val);
- }
- }
- private static short[] toList(HashMap<String, Short> map) {
- short[] list = new short[map.size()];
- Arrays.fill(list, (short) -1);
- for (Entry<String, Short> entry : map.entrySet()) {
- list[entry.getValue()] = getStringID(entry.getKey());
- }
- return list;
- }
- //runtime cache
- private static String[] stringCache;
- protected static String getString(short stringID) {
- if (stringID == 0)
- return null;
- /*
- if (loadingProperties) {
- return stringTable.substring(stringIDs[stringID],
- stringIDs[stringID+1]);
- }
- */
- //sync if we want it to be MT-enabled
- if (stringCache[stringID] == null){
- stringCache[stringID] =
- new String (table_stringTable,
- table_stringIDs[stringID],
- table_stringIDs[stringID+1] - table_stringIDs[stringID]);
- }
- return stringCache[stringID];
- }
- private static short[] getShortArray(short shortArrayID) {
- String s = getString(shortArrayID);
- char[] cc = s.toCharArray();
- short[] ss = new short[cc.length];
- for (int i = 0; i < cc.length; i++) {
- ss[i] = (short)(cc[i] & 0xffff);
- }
- return ss;
- }
- private static short getStringID(String s) {
- if (s == null) {
- return (short)0;
- }
- short pos0 = (short)stringTable.length();
- stringTable.append(s);
- short pos1 = (short)stringTable.length();
- stringIDs[stringIDNum] = pos0;
- stringIDs[stringIDNum + 1] = pos1;
- stringIDNum++;
- if (stringIDNum + 1 >= stringIDs.length) {
- short[] tmp = new short[stringIDNum + 1000];
- System.arraycopy(stringIDs, 0, tmp, 0, stringIDNum);
- stringIDs = tmp;
- }
- return (short)(stringIDNum - 1);
- }
- private static short getShortArrayID(short sa[]) {
- char[] cc = new char[sa.length];
- for (int i = 0; i < sa.length; i ++) {
- cc[i] = (char)sa[i];
- }
- String s = new String(cc);
- return getStringID(s);
- }
- //utility "empty" objects
- private static final int[] EMPTY_INT_ARRAY = new int[0];
- private static final String[] EMPTY_STRING_ARRAY = new String[0];
- private static final short[] EMPTY_SHORT_ARRAY = new short[0];
- private static final String UNDEFINED_COMPONENT_FONT = "unknown";
- //////////////////////////////////////////////////////////////////////////
- //Convert the FontConfig data in Properties file to binary data tables //
- //////////////////////////////////////////////////////////////////////////
- static class PropertiesHandler {
- public void load(InputStream in) throws IOException {
- initLogicalNameStyle();
- initHashMaps();
- FontProperties fp = new FontProperties();
- fp.load(in);
- initBinaryTable();
- }
- private void initBinaryTable() {
- //(0)
- head = new short[HEAD_LENGTH];
- head[INDEX_scriptIDs] = (short)HEAD_LENGTH;
- table_scriptIDs = toList(scriptIDs);
- //(1)a: scriptAllfonts scriptID/allfonts -> componentFontNameID
- // b: scriptFonts scriptID -> componentFontNameID[20]
- //if we have a "allfonts.script" def, then we just put
- //the "-platformFontID" value in the slot, otherwise the slot
- //value is "offset" which "offset" is where 20 entries located
- //in the table attached.
- head[INDEX_scriptFonts] = (short)(head[INDEX_scriptIDs] + table_scriptIDs.length);
- int len = table_scriptIDs.length + scriptFonts.size() * 20;
- table_scriptFonts = new short[len];
- for (Entry<Short, Short> entry : scriptAllfonts.entrySet()) {
- table_scriptFonts[entry.getKey().intValue()] = entry.getValue();
- }
- int off = table_scriptIDs.length;
- for (Entry<Short, Short[]> entry : scriptFonts.entrySet()) {
- table_scriptFonts[entry.getKey().intValue()] = (short)-off;
- Short[] v = entry.getValue();
- for (int i = 0; i < 20; i++) {
- if (v[i] != null) {
- table_scriptFonts[off++] = v[i];
- } else {
- table_scriptFonts[off++] = 0;
- }
- }
- }
- //(2)
- head[INDEX_elcIDs] = (short)(head[INDEX_scriptFonts] + table_scriptFonts.length);
- table_elcIDs = toList(elcIDs);
- //(3) sequences elcID -> XXXX[1|5] -> scriptID[]
- head[INDEX_sequences] = (short)(head[INDEX_elcIDs] + table_elcIDs.length);
- table_sequences = new short[elcIDs.size() * NUM_FONTS];
- for (Entry<Short, short[]> entry : sequences.entrySet()) {
- //table_sequences[entry.getKey().intValue()] = (short)-off;
- int k = entry.getKey().intValue();
- short[] v = entry.getValue();
- /*
- System.out.println("elc=" + k + "/" + getString((short)table_elcIDs[k]));
- short[] ss = getShortArray(v[0]);
- for (int i = 0; i < ss.length; i++) {
- System.out.println(" " + getString((short)table_scriptIDs[ss[i]]));
- }
- */
- if (v.length == 1) {
- //the "allfonts" entries
- for (int i = 0; i < NUM_FONTS; i++) {
- table_sequences[k * NUM_FONTS + i] = v[0];
- }
- } else {
- for (int i = 0; i < NUM_FONTS; i++) {
- table_sequences[k * NUM_FONTS + i] = v[i];
- }
- }
- }
- //(4)
- head[INDEX_fontfileNameIDs] = (short)(head[INDEX_sequences] + table_sequences.length);
- table_fontfileNameIDs = toList(fontfileNameIDs);
- //(5)
- head[INDEX_componentFontNameIDs] = (short)(head[INDEX_fontfileNameIDs] + table_fontfileNameIDs.length);
- table_componentFontNameIDs = toList(componentFontNameIDs);
- //(6)componentFontNameID -> filenameID
- head[INDEX_filenames] = (short)(head[INDEX_componentFontNameIDs] + table_componentFontNameIDs.length);
- table_filenames = new short[table_componentFontNameIDs.length];
- Arrays.fill(table_filenames, (short) -1);
- for (Entry<Short, Short> entry : filenames.entrySet()) {
- table_filenames[entry.getKey()] = entry.getValue();
- }
- //(7)scriptID-> awtfontpath
- //the paths are stored as scriptID -> stringID in awtfontpahts
- head[INDEX_awtfontpaths] = (short)(head[INDEX_filenames] + table_filenames.length);
- table_awtfontpaths = new short[table_scriptIDs.length];
- for (Entry<Short, Short> entry : awtfontpaths.entrySet()) {
- table_awtfontpaths[entry.getKey()] = entry.getValue();
- }
- //(8)exclusions
- head[INDEX_exclusions] = (short)(head[INDEX_awtfontpaths] + table_awtfontpaths.length);
- table_exclusions = new short[scriptIDs.size()];
- for (Entry<Short, int[]> entry : exclusions.entrySet()) {
- int[] exI = entry.getValue();
- char[] exC = new char[exI.length * 2];
- int j = 0;
- for (int i = 0; i < exI.length; i++) {
- exC[j++] = (char) (exI[i] >> 16);
- exC[j++] = (char) (exI[i] & 0xffff);
- }
- table_exclusions[entry.getKey()] = getStringID(new String (exC));
- }
- //(9)proportionals
- head[INDEX_proportionals] = (short)(head[INDEX_exclusions] + table_exclusions.length);
- table_proportionals = new short[proportionals.size() * 2];
- int j = 0;
- for (Entry<Short, Short> entry : proportionals.entrySet()) {
- table_proportionals[j++] = entry.getKey();
- table_proportionals[j++] = entry.getValue();
- }
- //(10) see (1) for info, the only difference is "xxx.motif"
- head[INDEX_scriptFontsMotif] = (short)(head[INDEX_proportionals] + table_proportionals.length);
- if (scriptAllfontsMotif.size() != 0 || scriptFontsMotif.size() != 0) {
- len = table_scriptIDs.length + scriptFontsMotif.size() * 20;
- table_scriptFontsMotif = new short[len];
- for (Entry<Short, Short> entry : scriptAllfontsMotif.entrySet()) {
- table_scriptFontsMotif[entry.getKey().intValue()] =
- (short)entry.getValue();
- }
- off = table_scriptIDs.length;
- for (Entry<Short, Short[]> entry : scriptFontsMotif.entrySet()) {
- table_scriptFontsMotif[entry.getKey().intValue()] = (short)-off;
- Short[] v = entry.getValue();
- int i = 0;
- while (i < 20) {
- if (v[i] != null) {
- table_scriptFontsMotif[off++] = v[i];
- } else {
- table_scriptFontsMotif[off++] = 0;
- }
- i++;
- }
- }
- } else {
- table_scriptFontsMotif = EMPTY_SHORT_ARRAY;
- }
- //(11)short[] alphabeticSuffix
- head[INDEX_alphabeticSuffix] = (short)(head[INDEX_scriptFontsMotif] + table_scriptFontsMotif.length);
- table_alphabeticSuffix = new short[alphabeticSuffix.size() * 2];
- j = 0;
- for (Entry<Short, Short> entry : alphabeticSuffix.entrySet()) {
- table_alphabeticSuffix[j++] = entry.getKey();
- table_alphabeticSuffix[j++] = entry.getValue();
- }
- //(15)short[] fallbackScriptIDs; just put the ID in head
- head[INDEX_fallbackScripts] = getShortArrayID(fallbackScriptIDs);
- //(16)appendedfontpath
- head[INDEX_appendedfontpath] = getStringID(appendedfontpath);
- //(17)version
- head[INDEX_version] = getStringID(version);
- //(12)short[] StringIDs
- head[INDEX_stringIDs] = (short)(head[INDEX_alphabeticSuffix] + table_alphabeticSuffix.length);
- table_stringIDs = new short[stringIDNum + 1];
- System.arraycopy(stringIDs, 0, table_stringIDs, 0, stringIDNum + 1);
- //(13)StringTable
- head[INDEX_stringTable] = (short)(head[INDEX_stringIDs] + stringIDNum + 1);
- table_stringTable = stringTable.toString().toCharArray();
- //(14)
- head[INDEX_TABLEEND] = (short)(head[INDEX_stringTable] + stringTable.length());
- //StringTable cache
- stringCache = new String[table_stringIDs.length];
- }
- //////////////////////////////////////////////
- private HashMap<String, Short> scriptIDs;
- //elc -> Encoding.Language.Country
- private HashMap<String, Short> elcIDs;
- //componentFontNameID starts from "1", "0" reserves for "undefined"
- private HashMap<String, Short> componentFontNameIDs;
- private HashMap<String, Short> fontfileNameIDs;
- private HashMap<String, Integer> logicalFontIDs;
- private HashMap<String, Integer> fontStyleIDs;
- //componentFontNameID -> fontfileNameID
- private HashMap<Short, Short> filenames;
- //elcID -> allfonts/logicalFont -> scriptID list
- //(1)if we have a "allfonts", then the length of the
- // value array is "1", otherwise it's 5, each font
- // must have their own individual entry.
- //scriptID list "short[]" is stored as an ID
- private HashMap<Short, short[]> sequences;
- //scriptID ->logicFontID/fontStyleID->componentFontNameID,
- //a 20-entry array (5-name x 4-style) for each script
- private HashMap<Short, Short[]> scriptFonts;
- //scriptID -> componentFontNameID
- private HashMap<Short, Short> scriptAllfonts;
- //scriptID -> exclusionRanges[]
- private HashMap<Short, int[]> exclusions;
- //scriptID -> fontpath
- private HashMap<Short, Short> awtfontpaths;
- //fontID -> fontID
- private HashMap<Short, Short> proportionals;
- //scriptID -> componentFontNameID
- private HashMap<Short, Short> scriptAllfontsMotif;
- //scriptID ->logicFontID/fontStyleID->componentFontNameID,
- private HashMap<Short, Short[]> scriptFontsMotif;
- //elcID -> stringID of alphabetic/XXXX
- private HashMap<Short, Short> alphabeticSuffix;
- private short[] fallbackScriptIDs;
- private String version;
- private String appendedfontpath;
- private void initLogicalNameStyle() {
- logicalFontIDs = new HashMap<String, Integer>();
- fontStyleIDs = new HashMap<String, Integer>();
- logicalFontIDs.put("serif", 0);
- logicalFontIDs.put("sansserif", 1);
- logicalFontIDs.put("monospaced", 2);
- logicalFontIDs.put("dialog", 3);
- logicalFontIDs.put("dialoginput",4);
- fontStyleIDs.put("plain", 0);
- fontStyleIDs.put("bold", 1);
- fontStyleIDs.put("italic", 2);
- fontStyleIDs.put("bolditalic", 3);
- }
- private void initHashMaps() {
- scriptIDs = new HashMap<String, Short>();
- elcIDs = new HashMap<String, Short>();
- componentFontNameIDs = new HashMap<String, Short>();
- /*Init these tables to allow componentFontNameID, fontfileNameIDs
- to start from "1".
- */
- componentFontNameIDs.put("", Short.valueOf((short)0));
- fontfileNameIDs = new HashMap<String, Short>();
- filenames = new HashMap<Short, Short>();
- sequences = new HashMap<Short, short[]>();
- scriptFonts = new HashMap<Short, Short[]>();
- scriptAllfonts = new HashMap<Short, Short>();
- exclusions = new HashMap<Short, int[]>();
- awtfontpaths = new HashMap<Short, Short>();
- proportionals = new HashMap<Short, Short>();
- scriptFontsMotif = new HashMap<Short, Short[]>();
- scriptAllfontsMotif = new HashMap<Short, Short>();
- alphabeticSuffix = new HashMap<Short, Short>();
- fallbackScriptIDs = EMPTY_SHORT_ARRAY;
- /*
- version
- appendedfontpath
- */
- }
- private int[] parseExclusions(String key, String exclusions) {
- if (exclusions == null) {
- return EMPTY_INT_ARRAY;
- }
- // range format is xxxx-XXXX,yyyyyy-YYYYYY,.....
- int numExclusions = 1;
- int pos = 0;
- while ((pos = exclusions.indexOf(',', pos)) != -1) {
- numExclusions++;
- pos++;
- }
- int[] exclusionRanges = new int[numExclusions * 2];
- pos = 0;
- int newPos = 0;
- for (int j = 0; j < numExclusions * 2; ) {
- String lower, upper;
- int lo = 0, up = 0;
- try {
- newPos = exclusions.indexOf('-', pos);
- lower = exclusions.substring(pos, newPos);
- pos = newPos + 1;
- newPos = exclusions.indexOf(',', pos);
- if (newPos == -1) {
- newPos = exclusions.length();
- }
- upper = exclusions.substring(pos, newPos);
- pos = newPos + 1;
- int lowerLength = lower.length();
- int upperLength = upper.length();
- if (lowerLength != 4 && lowerLength != 6
- || upperLength != 4 && upperLength != 6) {
- throw new Exception();
- }
- lo = Integer.parseInt(lower, 16);
- up = Integer.parseInt(upper, 16);
- if (lo > up) {
- throw new Exception();
- }
- } catch (Exception e) {
- if (FontUtilities.debugFonts() &&
- logger != null) {
- logger.config("Failed parsing " + key +
- " property of font configuration.");
- }
- return EMPTY_INT_ARRAY;
- }
- exclusionRanges[j++] = lo;
- exclusionRanges[j++] = up;
- }
- return exclusionRanges;
- }
- private Short getID(HashMap<String, Short> map, String key) {
- Short ret = map.get(key);
- if ( ret == null) {
- map.put(key, (short)map.size());
- return map.get(key);
- }
- return ret;
- }
- class FontProperties extends Properties {
- public synchronized Object put(Object k, Object v) {
- parseProperty((String)k, (String)v);
- return null;
- }
- }
- private void parseProperty(String key, String value) {
- if (key.startsWith("filename.")) {
- //the only special case is "MingLiu_HKSCS" which has "_" in its
- //facename, we dont want to replace the "_" with " "
- key = key.substring(9);
- if (!"MingLiU_HKSCS".equals(key)) {
- key = key.replace('_', ' ');
- }
- Short faceID = getID(componentFontNameIDs, key);
- Short fileID = getID(fontfileNameIDs, value);
- //System.out.println("faceID=" + faceID + "/" + key + " -> "
- // + "fileID=" + fileID + "/" + value);
- filenames.put(faceID, fileID);
- } else if (key.startsWith("exclusion.")) {
- key = key.substring(10);
- exclusions.put(getID(scriptIDs,key), parseExclusions(key,value));
- } else if (key.startsWith("sequence.")) {
- key = key.substring(9);
- boolean hasDefault = false;
- boolean has1252 = false;
- //get the scriptID list
- String[] ss = (String[])splitSequence(value).toArray(EMPTY_STRING_ARRAY);
- short [] sa = new short[ss.length];
- for (int i = 0; i < ss.length; i++) {
- if ("alphabetic/default".equals(ss[i])) {
- //System.out.println(key + " -> " + ss[i]);
- ss[i] = "alphabetic";
- hasDefault = true;
- } else if ("alphabetic/1252".equals(ss[i])) {
- //System.out.println(key + " -> " + ss[i]);
- ss[i] = "alphabetic";
- has1252 = true;
- }
- sa[i] = getID(scriptIDs, ss[i]).shortValue();
- //System.out.println("scriptID=" + si[i] + "/" + ss[i]);
- }
- //convert the "short[] -> string -> stringID"
- short scriptArrayID = getShortArrayID(sa);
- Short elcID = null;
- int dot = key.indexOf('.');
- if (dot == -1) {
- if ("fallback".equals(key)) {
- fallbackScriptIDs = sa;
- return;
- }
- if ("allfonts".equals(key)) {
- elcID = getID(elcIDs, "NULL.NULL.NULL");
- } else {
- if (logger != null) {
- logger.config("Error sequence def: <sequence." + key + ">");
- }
- return;
- }
- } else {
- elcID = getID(elcIDs, key.substring(dot + 1));
- //System.out.println("elcID=" + elcID + "/" + key.substring(dot + 1));
- key = key.substring(0, dot);
- }
- short[] scriptArrayIDs = null;
- if ("allfonts".equals(key)) {
- scriptArrayIDs = new short[1];
- scriptArrayIDs[0] = scriptArrayID;
- } else {
- scriptArrayIDs = sequences.get(elcID);
- if (scriptArrayIDs == null) {
- scriptArrayIDs = new short[5];
- }
- Integer fid = logicalFontIDs.get(key);
- if (fid == null) {
- if (logger != null) {
- logger.config("Unrecognizable logicfont name " + key);
- }
- return;
- }
- //System.out.println("sequence." + key + "/" + id);
- scriptArrayIDs[fid.intValue()] = scriptArrayID;
- }
- sequences.put(elcID, scriptArrayIDs);
- if (hasDefault) {
- alphabeticSuffix.put(elcID, getStringID("default"));
- } else
- if (has1252) {
- alphabeticSuffix.put(elcID, getStringID("1252"));
- }
- } else if (key.startsWith("allfonts.")) {
- key = key.substring(9);
- if (key.endsWith(".motif")) {
- key = key.substring(0, key.length() - 6);
- //System.out.println("motif: all." + key + "=" + value);
- scriptAllfontsMotif.put(getID(scriptIDs,key), getID(componentFontNameIDs,value));
- } else {
- scriptAllfonts.put(getID(scriptIDs,key), getID(componentFontNameIDs,value));
- }
- } else if (key.startsWith("awtfontpath.")) {
- key = key.substring(12);
- //System.out.println("scriptID=" + getID(scriptIDs, key) + "/" + key);
- awtfontpaths.put(getID(scriptIDs, key), getStringID(value));
- } else if ("version".equals(key)) {
- version = value;
- } else if ("appendedfontpath".equals(key)) {
- appendedfontpath = value;
- } else if (key.startsWith("proportional.")) {
- key = key.substring(13).replace('_', ' ');
- //System.out.println(key + "=" + value);
- proportionals.put(getID(componentFontNameIDs, key),
- getID(componentFontNameIDs, value));
- } else {
- //"name.style.script(.motif)", we dont care anything else
- int dot1, dot2;
- boolean isMotif = false;
- dot1 = key.indexOf('.');
- if (dot1 == -1) {
- if (logger != null) {
- logger.config("Failed parsing " + key +
- " property of font configuration.");
- }
- return;
- }
- dot2 = key.indexOf('.', dot1 + 1);
- if (dot2 == -1) {
- if (logger != null) {
- logger.config("Failed parsing " + key +
- " property of font configuration.");
- }
- return;
- }
- if (key.endsWith(".motif")) {
- key = key.substring(0, key.length() - 6);
- isMotif = true;
- //System.out.println("motif: " + key + "=" + value);
- }
- Integer nameID = logicalFontIDs.get(key.substring(0, dot1));
- Integer styleID = fontStyleIDs.get(key.substring(dot1+1, dot2));
- Short scriptID = getID(scriptIDs, key.substring(dot2 + 1));
- if (nameID == null || styleID == null) {
- if (logger != null) {
- logger.config("unrecognizable logicfont name/style at " + key);
- }
- return;
- }
- Short[] pnids;
- if (isMotif) {
- pnids = scriptFontsMotif.get(scriptID);
- } else {
- pnids = scriptFonts.get(scriptID);
- }
- if (pnids == null) {
- pnids = new Short[20];
- }
- pnids[nameID.intValue() * NUM_STYLES + styleID.intValue()]
- = getID(componentFontNameIDs, value);
- /*
- System.out.println("key=" + key + "/<" + nameID + "><" + styleID
- + "><" + scriptID + ">=" + value
- + "/" + getID(componentFontNameIDs, value));
- */
- if (isMotif) {
- scriptFontsMotif.put(scriptID, pnids);
- } else {
- scriptFonts.put(scriptID, pnids);
- }
- }
- }
- }
- }