Home | History | Annotate | Download | only in font
      1 /*
      2  *  Licensed to the Apache Software Foundation (ASF) under one or more
      3  *  contributor license agreements.  See the NOTICE file distributed with
      4  *  this work for additional information regarding copyright ownership.
      5  *  The ASF licenses this file to You under the Apache License, Version 2.0
      6  *  (the "License"); you may not use this file except in compliance with
      7  *  the License.  You may obtain a copy of the License at
      8  *
      9  *     http://www.apache.org/licenses/LICENSE-2.0
     10  *
     11  *  Unless required by applicable law or agreed to in writing, software
     12  *  distributed under the License is distributed on an "AS IS" BASIS,
     13  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     14  *  See the License for the specific language governing permissions and
     15  *  limitations under the License.
     16  */
     17 /**
     18  * @author Ilya S. Okomin
     19  * @version $Revision$
     20  */
     21 package org.apache.harmony.awt.gl.font;
     22 
     23 import java.awt.Font;
     24 import java.awt.peer.FontPeer;
     25 import java.io.File;
     26 import java.io.FileInputStream;
     27 import java.io.IOException;
     28 import java.lang.ref.ReferenceQueue;
     29 import java.lang.ref.SoftReference;
     30 import java.util.Enumeration;
     31 import java.util.Hashtable;
     32 import java.util.Locale;
     33 import java.util.Properties;
     34 import java.util.Vector;
     35 
     36 import org.apache.harmony.awt.gl.CommonGraphics2DFactory;
     37 import org.apache.harmony.luni.util.NotImplementedException;
     38 
     39 
     40 public abstract class FontManager {
     41 
     42     //???AWT
     43     boolean NOT_IMP = false;
     44 
     45     /**
     46      * array of font families names
     47      */
     48     public String[] allFamilies;
     49 
     50     public static final String DEFAULT_NAME = "Default"; /* Default font name */ //$NON-NLS-1$
     51     public static final String DIALOG_NAME = "Dialog";  /* Dialog font name */ //$NON-NLS-1$
     52 
     53     /**
     54      * Set of constants applicable to the TrueType 'name' table.
     55      */
     56     public static final byte  FAMILY_NAME_ID  = 1;      /* Family name identifier   */
     57     public static final byte  FONT_NAME_ID  = 4;        /* Full font name identifier    */
     58     public static final byte  POSTSCRIPT_NAME_ID = 6;   /* PostScript name identifier   */
     59     public static final short ENGLISH_LANGID = 0x0409;  /* English (United States)language identifier   */
     60 
     61     /**
     62      * Set of constants describing font type.
     63      */
     64     public static final byte  FONT_TYPE_TT  = 4;        /* TrueType type (TRUETYPE_FONTTYPE)    */
     65     public static final byte  FONT_TYPE_T1  = 2;        /* Type1 type    (DEVICE_FONTTYPE)      */
     66     public static final byte  FONT_TYPE_UNDEF  = 0;     /* Undefined type                       */
     67 
     68     // logical family types (indices in FontManager.LOGICAL_FONT_NAMES)
     69     static final int DIALOG = 3;        // FF_SWISS
     70     static final int SANSSERIF = 1;     // FF_SWISS
     71     static final int DIALOGINPUT = 4;   // FF_MODERN
     72     static final int MONOSPACED = 2;    // FF_MODERN
     73     static final int SERIF = 0;         // FF_ROMAN
     74 
     75 
     76     /**
     77      * FontProperty related constants.
     78      */
     79     public static final String PLATFORM_FONT_NAME = "PlatformFontName"; //$NON-NLS-1$
     80     public static final String LOGICAL_FONT_NAME = "LogicalFontName"; //$NON-NLS-1$
     81     public static final String COMPONENT_INDEX = "ComponentIndex"; //$NON-NLS-1$
     82     public static final String STYLE_INDEX = "StyleIndex"; //$NON-NLS-1$
     83 
     84     public static final String[] FONT_MAPPING_KEYS = {
     85             "LogicalFontName.StyleName.ComponentIndex", "LogicalFontName.ComponentIndex" //$NON-NLS-1$ //$NON-NLS-2$
     86     };
     87 
     88     public static final String FONT_CHARACTER_ENCODING = "fontcharset.LogicalFontName.ComponentIndex"; //$NON-NLS-1$
     89 
     90     public static final String EXCLUSION_RANGES = "exclusion.LogicalFontName.ComponentIndex"; //$NON-NLS-1$
     91 
     92     public static final String FONT_FILE_NAME = "filename.PlatformFontName"; //$NON-NLS-1$
     93 
     94     /**
     95      * Available logical font families names.
     96      */
     97     public static final String[] LOGICAL_FONT_FAMILIES = {
     98             "Serif", "SansSerif", "Monospaced", "Dialog", "DialogInput" //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$
     99     };
    100 
    101     /**
    102      * Available logical font names.
    103      */
    104     public static final String[] LOGICAL_FONT_NAMES = {
    105             "serif", "serif.plain", "serif.bold", "serif.italic", "serif.bolditalic", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$
    106             "sansserif", "sansserif.plain", "sansserif.bold", "sansserif.italic", "sansserif.bolditalic", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$
    107             "monospaced", "monospaced.plain", "monospaced.bold", "monospaced.italic", "monospaced.bolditalic", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$
    108             "dialog", "dialog.plain", "dialog.bold", "dialog.italic", "dialog.bolditalic", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$
    109             "dialoginput", "dialoginput.plain", "dialoginput.bold", "dialoginput.italic", "dialoginput.bolditalic" //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$
    110     };
    111 
    112     /**
    113      * Available logical font face names.
    114      */
    115     public static final String[] LOGICAL_FONT_FACES = {
    116             "Serif", "Serif.plain", "Serif.bold", "Serif.italic", "Serif.bolditalic", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$
    117             "Sansserif", "Sansserif.plain", "Sansserif.bold", "Sansserif.italic", "Sansserif.bolditalic", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$
    118             "Monospaced", "Monospaced.plain", "Monospaced.bold", "Monospaced.italic", "Monospaced.bolditalic", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$
    119             "Dialog", "Dialog.plain", "Dialog.bold", "Dialog.italic", "Dialog.bolditalic", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$
    120             "Dialoginput", "Dialoginput.plain", "Dialoginput.bold", "Dialoginput.italic", "Dialoginput.bolditalic" //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$
    121     };
    122 
    123     /**
    124      * Set of font style names.
    125      * Font.getStyle() corresponds to indexes in STYLE_NAMES array.
    126      */
    127     public static final String[] STYLE_NAMES = {
    128             "plain", "bold", "italic", "bolditalic" //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
    129     };
    130 
    131     /**
    132      * Logical font styles names table where font styles names used
    133      * as the key and the value is the index of this style name.
    134      */
    135     private static final Hashtable<String, Integer> style_keys = new Hashtable<String, Integer>(4);
    136 
    137     /**
    138      * Initialize font styles keys table.
    139      */
    140     static {
    141         for (int i = 0; i < STYLE_NAMES.length; i++){
    142             style_keys.put(STYLE_NAMES[i], Integer.valueOf(i));
    143         }
    144     }
    145 
    146     /**
    147      * Return font style from the logical style name.
    148      *
    149      * @param lName style name of the logical face
    150      */
    151     public static int getLogicalStyle(String lName){
    152         Integer value = style_keys.get(lName);
    153         return value != null ? value.intValue(): -1;
    154     }
    155 
    156     /**
    157      * Set of possible "os" property values.
    158      */
    159     public static final String[] OS_VALUES = {
    160             "NT", "98", "2000", "Me", "XP", // For Windows //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$
    161             "Redhat", "Turbo", "SuSE"       // For Linux //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
    162     };
    163 
    164     /**
    165      * Set of possible font.property file names.
    166      * Language, Country, Encoding, OS, Version should be replaced with
    167      * the values from current configuration.
    168      */
    169     public static final String[] FP_FILE_NAMES = {
    170             "/lib/font.properties.Language_Country_Encoding.OSVersion", //$NON-NLS-1$
    171             "/lib/font.properties.Language_Country_Encoding.OS", //$NON-NLS-1$
    172             "/lib/font.properties.Language_Country_Encoding.Version", //$NON-NLS-1$
    173             "/lib/font.properties.Language_Country_Encoding", //$NON-NLS-1$
    174             "/lib/font.properties.Language_Country.OSVersion", //$NON-NLS-1$
    175             "/lib/font.properties.Language_Country.OS", //$NON-NLS-1$
    176             "/lib/font.properties.Language_Country.Version", //$NON-NLS-1$
    177             "/lib/font.properties.Language_Country", //$NON-NLS-1$
    178             "/lib/font.properties.Language_Encoding.OSVersion", //$NON-NLS-1$
    179             "/lib/font.properties.Language_Encoding.OS", //$NON-NLS-1$
    180             "/lib/font.properties.Language_Encoding.Version", //$NON-NLS-1$
    181             "/lib/font.properties.Language_Encoding", //$NON-NLS-1$
    182             "/lib/font.properties.Language.OSVersion", //$NON-NLS-1$
    183             "/lib/font.properties.Language.OS", //$NON-NLS-1$
    184             "/lib/font.properties.Language.Version", //$NON-NLS-1$
    185             "/lib/font.properties.Language", //$NON-NLS-1$
    186             "/lib/font.properties.Encoding.OSVersion", //$NON-NLS-1$
    187             "/lib/font.properties.Encoding.OS", //$NON-NLS-1$
    188             "/lib/font.properties.Encoding.Version", //$NON-NLS-1$
    189             "/lib/font.properties.Encoding", //$NON-NLS-1$
    190             "/lib/font.properties.OSVersion", //$NON-NLS-1$
    191             "/lib/font.properties.OS", //$NON-NLS-1$
    192             "/lib/font.properties.Version", //$NON-NLS-1$
    193             "/lib/font.properties" //$NON-NLS-1$
    194     };
    195 
    196     /**
    197      * Table with all available font properties corresponding
    198      * to the current system configuration.
    199      */
    200     public Hashtable<String, Vector<FontProperty>> fProperties = new Hashtable<String, Vector<FontProperty>>();
    201 
    202     public FontManager(){
    203         allFamilies = getAllFamilies();
    204         /*
    205          * Creating and registering shutdown hook to free resources
    206          * before object is destroyed.
    207          */
    208         //???AWT
    209         //DisposeNativeHook shutdownHook = new DisposeNativeHook();
    210         //Runtime.getRuntime().addShutdownHook(shutdownHook);
    211     }
    212 
    213     /**
    214      * Maximum number of unreferenced font peers to keep.
    215      */
    216     public static final int EMPTY_FONTS_CAPACITY = 10;
    217 
    218     /**
    219      * Locale - Language ID hash table.
    220      */
    221     Hashtable<String, Short> tableLCID = new Hashtable<String, Short>();
    222 
    223     /**
    224      * Hash table that contains FontPeers instances.
    225      */
    226     public Hashtable<String, HashMapReference> fontsTable = new Hashtable<String, HashMapReference>();
    227 
    228     /**
    229      * ReferenceQueue for HashMapReference objects to check
    230      * if they were collected by garbage collector.
    231      */
    232     public ReferenceQueue<FontPeer> queue = new ReferenceQueue<FontPeer>();
    233 
    234     /**
    235      * Singleton instance
    236      */
    237     public final static FontManager inst = CommonGraphics2DFactory.inst.getFontManager();
    238 
    239     /**
    240      * Gets singleton instance of FontManager
    241      *
    242      * @return instance of FontManager implementation
    243      */
    244     public static FontManager getInstance() {
    245         return inst;
    246     }
    247 
    248     /**
    249      * Returns platform-dependent Font peer created from the specified
    250      * Font object from the table with cached FontPeers instances.
    251      *
    252      * Note, this method checks whether FontPeer with specified parameters
    253      * exists in the table with cached FontPeers' instances. If there is no needed
    254      * instance - it is created and cached.
    255      *
    256      * @param fontName name of the font
    257      * @param _fontStyle style of the font
    258      * @param size font size
    259      *
    260      * @return platform dependent FontPeer implementation created from
    261      * the specified parameters
    262      */
    263     public FontPeer getFontPeer(String fontName, int _fontStyle, int size) {
    264         updateFontsTable();
    265 
    266         FontPeer peer = null;
    267         String key;
    268         String name;
    269         int fontStyle = _fontStyle;
    270 
    271         int logicalIndex = getLogicalFaceIndex(fontName);
    272 
    273         if (logicalIndex != -1){
    274             name = getLogicalFaceFromFont(fontStyle, logicalIndex);
    275             fontStyle = getStyleFromLogicalFace(name);
    276             key = name.concat(String.valueOf(size));
    277         } else {
    278             name = fontName;
    279             key = name.concat(String.valueOf(fontStyle)).
    280                     concat(String.valueOf(size));
    281         }
    282 
    283         HashMapReference hmr   = fontsTable.get(key);
    284         if (hmr != null) {
    285             peer = hmr.get();
    286         }
    287 
    288         if (peer == null) {
    289             peer = createFontPeer(name, fontStyle, size, logicalIndex);
    290             if (peer == null){
    291                 peer = getFontPeer(DIALOG_NAME, fontStyle, size);
    292             }
    293             fontsTable.put(key, new HashMapReference(key, peer, queue));
    294         }
    295 
    296         return peer;
    297     }
    298 
    299     /**
    300      * Returns instance of font peer (logical or physical) according to the
    301      * specified parameters.
    302      *
    303      * @param name font face name
    304      * @param style style of the font
    305      * @param size size of the font
    306      * @param logicalIndex index of the logical face name in LOGICAL_FONT_FACES
    307      * array or -1 if desired font peer is not logical.
    308      */
    309     private FontPeer createFontPeer(String name, int style, int size, int logicalIndex){
    310         FontPeer peer;
    311         if (logicalIndex != -1){
    312             peer = createLogicalFontPeer(name, style, size);
    313         }else {
    314             peer = createPhysicalFontPeer(name, style, size);
    315         }
    316 
    317         return peer;
    318     }
    319 
    320     /**
    321      * Returns family name for logical face names as a parameter.
    322      *
    323      * @param faceName logical font face name
    324      */
    325     public String getFamilyFromLogicalFace(String faceName){
    326         int pos = faceName.indexOf("."); //$NON-NLS-1$
    327         if (pos == -1){
    328             return faceName;
    329         }
    330 
    331         return faceName.substring(0, pos);
    332     }
    333 
    334     /**
    335      * Returns new logical font peer for the parameters specified using font
    336      * properties.
    337      *
    338      * @param faceName face name of the logical font
    339      * @param style style of the font
    340      * @param size font size
    341      *
    342      */
    343     private FontPeer createLogicalFontPeer(String faceName, int style, int size){
    344         String family = getFamilyFromLogicalFace(faceName);
    345         FontProperty[] fps = getFontProperties(family.toLowerCase() + "." + style); //$NON-NLS-1$
    346         if (fps != null){
    347             int numFonts = fps.length;
    348             FontPeerImpl[] physicalFonts = new FontPeerImpl[numFonts];
    349             for (int i = 0; i < numFonts; i++){
    350                 FontProperty fp = fps[i];
    351 
    352                 String name = fp.getName();
    353                 int fpStyle = fp.getStyle();
    354                 String key = name.concat(String.valueOf(fpStyle)).
    355                     concat(String.valueOf(size));
    356 
    357                 HashMapReference hmr   = fontsTable.get(key);
    358                 if (hmr != null) {
    359                     physicalFonts[i] = (FontPeerImpl)hmr.get();
    360                 }
    361 
    362                 if (physicalFonts[i] == null){
    363                     physicalFonts[i] = (FontPeerImpl)createPhysicalFontPeer(name, fpStyle, size);
    364                     fontsTable.put(key, new HashMapReference(key, physicalFonts[i], queue));
    365                 }
    366 
    367                 if (physicalFonts[i] == null){
    368                     physicalFonts[i] = (FontPeerImpl)getDefaultFont(style, size);
    369                 }
    370             }
    371             return new CompositeFont(family, faceName, style, size, fps, physicalFonts);
    372         }
    373 
    374         // if there is no property for this logical font - default font is to be
    375         // created
    376         FontPeerImpl peer = (FontPeerImpl)getDefaultFont(style, size);
    377 
    378         return peer;
    379     }
    380 
    381     /**
    382      * Returns new physical font peer for the parameters specified using font properties
    383      * This method must be overridden by subclasses implementations.
    384      *
    385      * @param faceName face name or family name of the font
    386      * @param style style of the font
    387      * @param size font size
    388      *
    389      */
    390     public abstract FontPeer createPhysicalFontPeer(String name, int style, int size);
    391 
    392     /**
    393      * Returns default font peer class with "Default" name that is usually
    394      * used when font with specified font names and style doesn't exsist
    395      * on a system.
    396      *
    397      * @param style style of the font
    398      * @param size size of the font
    399      */
    400     public FontPeer getDefaultFont(int style, int size){
    401         updateFontsTable();
    402 
    403         FontPeer peer = null;
    404         String key = DEFAULT_NAME.concat(String.valueOf(style)).
    405                     concat(String.valueOf(size));
    406 
    407         HashMapReference hmr   = fontsTable.get(key);
    408         if (hmr != null) {
    409             peer = hmr.get();
    410         }
    411 
    412         if (peer == null) {
    413             peer = createDefaultFont(style, size);
    414 
    415             ((FontPeerImpl)peer).setFamily(DEFAULT_NAME);
    416             ((FontPeerImpl)peer).setPSName(DEFAULT_NAME);
    417             ((FontPeerImpl)peer).setFontName(DEFAULT_NAME);
    418 
    419             fontsTable.put(key, new HashMapReference(key, peer, queue));
    420         }
    421 
    422         return peer;
    423     }
    424 
    425     /**
    426      *
    427      * Returns new default font peer with "Default" name for the parameters
    428      * specified. This method must be overridden by subclasses implementations.
    429      *
    430      * @param style style of the font
    431      * @param size size of the font
    432      */
    433     public abstract FontPeer createDefaultFont(int style, int size);
    434 
    435     /**
    436      * Returns face name of the logical font, which is the result
    437      * of specified font style and face style union.
    438      *
    439      * @param fontStyle specified style of the font
    440      * @param logicalIndex index of the specified face from the
    441      * LOGICAL_FONT_FACES array
    442      * @return resulting face name
    443      */
    444     public String getLogicalFaceFromFont(int fontStyle, int logicalIndex){
    445         int style = 0;
    446         String name = LOGICAL_FONT_FACES[logicalIndex];
    447         int pos = name.indexOf("."); //$NON-NLS-1$
    448 
    449         if (pos == -1){
    450             return createLogicalFace(name, fontStyle);
    451         }
    452 
    453         String styleName = name.substring(pos+1);
    454         name = name.substring(0, pos);
    455 
    456         // appending font style to the face style
    457         style = fontStyle | getLogicalStyle(styleName);
    458 
    459         return createLogicalFace(name, style);
    460     }
    461 
    462     /**
    463      * Function returns style value from logical face name.
    464      *
    465      * @param name face name
    466      * @return font style
    467      */
    468     public int getStyleFromLogicalFace(String name){
    469         int style;
    470         int pos = name.indexOf("."); //$NON-NLS-1$
    471 
    472         if (pos == -1){
    473             return Font.PLAIN;
    474         }
    475 
    476         String styleName = name.substring(pos+1);
    477 
    478         style = getLogicalStyle(styleName);
    479 
    480         return style;
    481     }
    482 
    483     /**
    484      * Returns logical face name corresponding to the logical
    485      * family name and style of the font.
    486      *
    487      * @param family font family
    488      * @param styleIndex index of the style name from the STYLE_NAMES array
    489      */
    490     public String createLogicalFace(String family, int styleIndex){
    491         return family + "." + STYLE_NAMES[styleIndex]; //$NON-NLS-1$
    492     }
    493 
    494     /**
    495      * Return language Id from LCID hash corresponding to the specified locale
    496      *
    497      * @param l specified locale
    498      */
    499     public Short getLCID(Locale l){
    500         if (this.tableLCID.size() == 0){
    501             initLCIDTable();
    502         }
    503 
    504         return tableLCID.get(l.toString());
    505     }
    506 
    507     /**
    508      * Platform-dependent LCID table init.
    509      */
    510     public abstract void initLCIDTable();
    511 
    512     /**
    513      * Freeing native resources. This hook is used to avoid
    514      * sudden application exit and to free resources created in native code.
    515      */
    516     private class DisposeNativeHook extends Thread {
    517 
    518         @Override
    519         public void run() {
    520             try{
    521                 /* Disposing native font peer's resources */
    522                 Enumeration<String> kEnum = fontsTable.keys();
    523 
    524                 while(kEnum.hasMoreElements()){
    525                     Object key = kEnum.nextElement();
    526                     HashMapReference hmr = fontsTable.remove(key);
    527                     FontPeerImpl delPeer = (FontPeerImpl)hmr.get();
    528 
    529                     if ((delPeer != null) && (delPeer.getClass() != CompositeFont.class)){
    530                         // there's nothing to dispose in CompositeFont objects
    531                         delPeer.dispose();
    532                     }
    533                 }
    534             } catch (Throwable t){
    535                 throw new RuntimeException(t);
    536             }
    537         }
    538       }
    539 
    540     /**
    541      * Returns File object, created in a directory
    542      * according to the System, where JVM is being ran.
    543      *
    544      * In Linux case we use ".fonts" directory (for fontconfig purpose),
    545      * where font file from the stream will be stored, hence in LinuxFontManager this
    546      * method is overridden.
    547      * In Windows case we use Windows temp directory (default implementation)
    548      *
    549      */
    550     public File getTempFontFile()throws IOException{
    551         //???AWT
    552         /*
    553         File fontFile = File.createTempFile("jFont", ".ttf"); //$NON-NLS-1$ //$NON-NLS-2$
    554         fontFile.deleteOnExit();
    555 
    556         return fontFile;
    557          */
    558         if(NOT_IMP)
    559             throw new NotImplementedException("getTempFontFile not Implemented");
    560         return null;
    561     }
    562 
    563     /**
    564      * Returns File object with font properties. It's name obtained using current
    565      * system configuration properties and locale settings. If no appropriate
    566      * file is found method returns null.
    567      */
    568     public static File getFontPropertyFile(){
    569         File file = null;
    570 
    571         String javaHome = System.getProperty("java.home"); //$NON-NLS-1$
    572         Locale l = Locale.getDefault();
    573         String language = l.getLanguage();
    574         String country = l.getCountry();
    575         String fileEncoding = System.getProperty("file.encoding"); //$NON-NLS-1$
    576 
    577         String os = System.getProperty("os.name"); //$NON-NLS-1$
    578 
    579         int i = 0;
    580 
    581         // OS names from system properties don't match
    582         // OS identifiers used in font.property files
    583         for (; i < OS_VALUES.length; i++){
    584             if (os.endsWith(OS_VALUES[i])){
    585                 os = OS_VALUES[i];
    586                 break;
    587             }
    588         }
    589 
    590         if (i == OS_VALUES.length){
    591             os = null;
    592         }
    593 
    594         String version = System.getProperty("os.version"); //$NON-NLS-1$
    595         String pathname;
    596 
    597         for (i = 0; i < FP_FILE_NAMES.length; i++){
    598             pathname = FP_FILE_NAMES[i];
    599             if (os != null){
    600                 pathname = pathname.replaceFirst("OS", os); //$NON-NLS-1$
    601             }
    602 
    603             pathname = javaHome + pathname;
    604 
    605             pathname = pathname.replaceAll("Language", language). //$NON-NLS-1$
    606                                 replaceAll("Country", country). //$NON-NLS-1$
    607                                 replaceAll("Encoding", fileEncoding). //$NON-NLS-1$
    608                                 replaceAll("Version", version); //$NON-NLS-1$
    609 
    610             file = new File(pathname);
    611 
    612             if (file.exists()){
    613                 break;
    614             }
    615         }
    616 
    617         return file.exists() ? file : null;
    618     }
    619 
    620     /**
    621      * Returns an array of integer range values
    622      * if the parameter exclusionString has format:
    623      *          Range
    624      *          Range [, exclusionString]
    625      *
    626      *          Range:
    627      *              Char-Char
    628      *
    629      *          Char:
    630      *              HexDigit HexDigit HexDigit HexDigit
    631      *
    632      * Method returns null if the specified string is null.
    633      *
    634      * @param exclusionString string parameter in specified format
    635      */
    636     public static int[] parseIntervals(String exclusionString){
    637         int[] results = null;
    638 
    639         if (exclusionString == null){
    640             return null;
    641         }
    642 
    643         String[] intervals = exclusionString.split(","); //$NON-NLS-1$
    644 
    645         if (intervals != null){
    646             int num = intervals.length;
    647             if (num > 0){
    648                 results = new int[intervals.length << 1];
    649                 for (int i = 0; i < intervals.length; i++){
    650                     String ranges[] = intervals[i].split("-"); //$NON-NLS-1$
    651                     results[i*2] = Integer.parseInt(ranges[0], 16);
    652                     results[i*2+1] = Integer.parseInt(ranges[1], 16);
    653 
    654                 }
    655             }
    656         }
    657         return results;
    658     }
    659 
    660     /**
    661      * Returns Properties from the properties file or null if
    662      * there is an error with FileInputStream processing.
    663      *
    664      * @param file File object containing properties
    665      */
    666     public static Properties getProperties(File file){
    667         Properties props = null;
    668         FileInputStream fis = null;
    669         try{
    670             fis = new FileInputStream(file);
    671             props = new Properties();
    672             props.load(fis);
    673         } catch (Exception e){
    674             System.out.println(e);
    675         }
    676         return props;
    677     }
    678 
    679     /**
    680      * Returns an array of FontProperties from the properties file
    681      * with the specified property name "logical face.style". E.g.
    682      * "dialog.2" corresponds to the font family Dialog with bold style.
    683      *
    684      * @param fpName key of the font properties in the properties set
    685      */
    686     public FontProperty[] getFontProperties(String fpName){
    687         Vector<FontProperty> props = fProperties.get(fpName);
    688 
    689         if (props == null){
    690             return null;
    691         }
    692 
    693         int size =  props.size();
    694 
    695         if (size == 0){
    696             return null;
    697         }
    698 
    699         FontProperty[] fps = new FontProperty[size];
    700         for (int i=0; i < fps.length; i++){
    701             fps[i] = props.elementAt(i);
    702         }
    703         return fps;
    704     }
    705 
    706     /**
    707      * Returns index of the font name in array of font names or -1 if
    708      * this font is not logical.
    709      *
    710      * @param fontName specified font name
    711      */
    712     public static int getLogicalFaceIndex(String fontName){
    713         for (int i=0; i<LOGICAL_FONT_NAMES.length; i++ ){
    714             if (LOGICAL_FONT_NAMES[i].equalsIgnoreCase(fontName)){
    715                 return i;
    716             }
    717         }
    718         return -1;
    719     }
    720 
    721     /**
    722      * Returns true if specified family name is available in this
    723      * GraphicsEnvironment.
    724      *
    725      * @param familyName the specified font family name
    726      */
    727     public boolean isFamilyExist(String familyName){
    728         return (getFamilyIndex(familyName) != -1);
    729     }
    730 
    731     /**
    732      * Returns index of family name from the array of family names available in
    733      * this GraphicsEnvironment or -1 if no family name was found.
    734      *
    735      * @param familyName specified font family name
    736      */
    737     public int getFamilyIndex(String familyName){
    738         for (int i=0; i<allFamilies.length; i++ ){
    739             if (familyName.equalsIgnoreCase(allFamilies[i])){
    740                 return i;
    741             }
    742         }
    743         return -1;
    744     }
    745 
    746     /**
    747      * Returns family with index specified from the array of family names available in
    748      * this GraphicsEnvironment.
    749      *
    750      * @param index index of the family in families names array
    751      */
    752     public String getFamily(int index){
    753         return allFamilies[index];
    754     }
    755     /**
    756      * Returns index of face name from the array of face names available in
    757      * this GraphicsEnvironment or -1 if no face name was found. Default return
    758      * value is -1, method must be overridden by FontManager implementation.
    759      *
    760      * @param faceName font face name which index is to be searched
    761      */
    762     public int getFaceIndex(String faceName){
    763         return -1;
    764     }
    765 
    766     public abstract String[] getAllFamilies();
    767 
    768     public abstract Font[] getAllFonts();
    769 
    770     /**
    771      * Class contains SoftReference instance that can be stored in the
    772      * Hashtable by means of key field corresponding to it.
    773      */
    774     private class HashMapReference extends SoftReference<FontPeer> {
    775 
    776         /**
    777          * The key for Hashtable.
    778          */
    779         private final String key;
    780 
    781         /**
    782          * Creates a new soft reference with the key specified and
    783          * adding this reference in the reference queue specified.
    784          *
    785          * @param key the key in Hashtable
    786          * @param value object that corresponds to the key
    787          * @param queue reference queue where reference is to be added
    788          */
    789         public HashMapReference(final String key, final FontPeer value,
    790                               final ReferenceQueue<FontPeer> queue) {
    791             super(value, queue);
    792             this.key = key;
    793         }
    794 
    795         /**
    796          * Returns the key that corresponds to the SoftReference instance
    797          *
    798          * @return the key in Hashtable with cached references
    799          */
    800         public Object getKey() {
    801             return key;
    802         }
    803     }
    804 
    805     /**
    806      * Removes keys from the Hashtable with font peers which corresponding
    807      * HashMapReference objects were garbage collected.
    808      */
    809     private void updateFontsTable() {
    810         HashMapReference r;
    811         //???AWT
    812         //while ((r = (HashMapReference)queue.poll()) != null) {
    813         //    fontsTable.remove(r.getKey());
    814         //}
    815     }
    816 
    817 }
    818 
    819 
    820