View Javadoc

    1   /*
    2    * All Rights Reserved.
    3    * Copyright (C) 1999-2005 Tsukuba Bunko.
    4    *
    5    * Licensed under the BSD License ("the License"); you may not use
    6    * this file except in compliance with the License.
    7    * You may obtain a copy of the License at
    8    *
    9    *       http://www.tsukuba-bunko.org/licenses/LICENSE.txt
    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   * $Id: FontManager.java,v 1.4 2005/11/09 10:39:37 ppoi Exp $
    18   */
    19  package tsukuba_bunko.peko.resource;
    20
    21  import	java.awt.Font;
    22  import	java.awt.GraphicsEnvironment;
    23  import	java.awt.font.TextAttribute;
    24
    25  import java.io.File;
    26  import	java.io.InputStream;
    27
    28  import	java.net.URL;
    29
    30  import	java.util.Iterator;
    31  import	java.util.Map;
    32  import	java.util.List;
    33  import	java.util.Locale;
    34  import	java.util.Set;
    35
    36  import	tsukuba_bunko.peko.Logger;
    37
    38  import	tsukuba_bunko.peko.resource.ResourceManager;
    39
    40
    41  /***
    42   * フォントの管理を提供します。
    43   * @author	$Author: ppoi $
    44   * @version	$Revision: 1.4 $
    45   */
    46  public class FontManager	{
    47
    48  	/***
    49  	 * 唯一のインスタンス
    50  	 */
    51  	private static FontManager	_instance = null;
    52
    53
    54  	/***
    55  	 * フォントキャッシュ
    56  	 */
    57  	private Map	_fonts = null;
    58
    59  	/***
    60  	 * 使用可能なフォントファミリセット
    61  	 */
    62  	private	Set	_fontFamilies = null;
    63
    64  	/***
    65  	 * 新規に作成したフォント
    66  	 */
    67  	private Map	_bundledFonts = null;
    68
    69
    70  	/***
    71  	 * <code>FontManager</code> のインスタンスを作成します。
    72  	 */
    73  	protected FontManager()
    74  	{
    75  		super();
    76  	}
    77
    78
    79  	/***
    80  	 * <code>attributes</code> で指定された属性を持つフォントを取得します。
    81  	 * @param	attributes	フォントに適用される属性マップ
    82  	 * @return	取得されたフォント
    83  	 */
    84  	public Font getFont( Map attributes )
    85  	{
    86  		Font	font = (Font)_fonts.get( attributes );
    87  		if( font == null )	{
    88  			String	family = (String)attributes.get( TextAttribute.FAMILY );
    89  			Logger.debug( "[font] search font: \"" + family + "\"" );
    90  			if( family == null )	{
    91  				Logger.debug( "[font] not specified font family. using serif family (default)" );
    92  				attributes.put( TextAttribute.FAMILY, "Serif" );
    93  			}
    94
    95  			if( _bundledFonts.keySet().contains(family) )	{
    96  				Logger.debug( "[font] using bundled font" );
    97  				attributes.remove( TextAttribute.FAMILY );
    98  				font = ((Font)_bundledFonts.get(family)).deriveFont( attributes );
    99  				attributes.put( TextAttribute.FAMILY, family );
    100 			}
    101 			else if( _fontFamilies.contains(family) )	{
    102 				Logger.debug( "[font] using system family" );
    103 				font = new Font( attributes );
    104 			}
    105 			else	{
    106 				Logger.error( "[font] invalid font family specified. family=" + family );
    107 				Logger.debug( "[font] using serif family (default)" );
    108 				attributes.remove( TextAttribute.FAMILY );
    109 				font = new Font("Serif", 1, Font.PLAIN).deriveFont( attributes );
    110 				attributes.put( TextAttribute.FAMILY, family );
    111 			}
    112 			_fonts.put( attributes, font );
    113 		}
    114 		return font;
    115 	}
    116
    117 	/***
    118 	 * 初期化
    119 	 */
    120 	private void initialize()
    121 	{
    122 		ResourceManager	resources = ResourceManager.getInstance();
    123
    124 		_fontFamilies = new java.util.HashSet( 89 );
    125
    126 		Locale	locale = (Locale)resources.getResource( "peko.system.locale" );
    127 		if( locale == null )	{
    128 			locale = Locale.getDefault();
    129 		}
    130 		String[]	families = GraphicsEnvironment.getLocalGraphicsEnvironment().getAvailableFontFamilyNames( locale );
    131 		for( int i = 0; i < families.length; ++i )	{
    132 			_fontFamilies.add( families[i] );
    133 		}
    134
    135 		boolean	isJ5 = false;
    136 		try	{
    137 			Font.class.getMethod( "createFont", new Class[]{int.class, File.class} );
    138 			isJ5 = true;
    139 		}
    140 		catch( Exception e )	{
    141 			//ignore
    142 		}
    143
    144 		_bundledFonts = new java.util.HashMap( 89 );
    145 		List	additional = (List)resources.getResource( "peko.system.fonts", true );
    146 		if( (additional != null) && !additional.isEmpty() )	{
    147 			InputStream	fontStream = null;
    148 			URL	basedir = resources.getLocationResources().getMiscDirecotryURL();
    149 			String	fontPath = null;
    150 			Iterator	itr = additional.iterator();
    151 			while( itr.hasNext() )	{
    152 				try	{
    153 					fontPath = (String)itr.next();
    154 					if( (fontPath == null) || (fontPath.length() == 0) )	{
    155 						continue;
    156 					}
    157 					Logger.debug( "[font] loading font \"" + fontPath + "\"." );
    158 					Font	font = null;
    159 					URL	fontURL = new URL( basedir, fontPath );
    160 					String	protocol = fontURL.getProtocol();
    161 					if( isJ5 && "file".equals(protocol) )	{
    162 						File	fontFile = new File( fontURL.getFile() );
    163 						font = Font.createFont( Font.TRUETYPE_FONT, fontFile );
    164 					}
    165 					else	{
    166 						fontStream = fontURL.openStream();
    167 						font = Font.createFont(Font.TRUETYPE_FONT, fontStream );
    168 					}
    169 					String	fontName = fontPath;
    170 					int	extDelim = fontName.lastIndexOf( '.' );
    171 					if( extDelim != -1 )	{
    172 						fontName = fontName.substring( 0, extDelim );
    173 					}
    174 					_bundledFonts.put( fontName, font );
    175 					_bundledFonts.put( (String)font.getAttributes().get(TextAttribute.FAMILY), font );	//下方互換のため
    176 				}
    177 				catch( Exception e )	{
    178 					Logger.warn( "[font] fail to load font \"" + fontPath + "\".", e );
    179 				}
    180 				finally	{
    181 					if( fontStream != null )	{
    182 						try	{
    183 							fontStream.close();
    184 						}
    185 						catch( Exception e )	{
    186 							Logger.error( "[font] fail to close font stream. \"" + fontPath + "\".", e );
    187 						}
    188 						fontStream = null;
    189 					}
    190 				}
    191 			}
    192 		}
    193
    194 		_fonts = new java.util.WeakHashMap( 89 );
    195 	}
    196
    197
    198
    199 	/***
    200 	 * 唯一の <code>FontManager</code> インスタンスを取得します。
    201 	 * @return	唯一の <code>FontManager</code> インスタンス
    202 	 */
    203 	public static FontManager getInstance()
    204 	{
    205 		if( _instance == null )	{
    206 			synchronized( FontManager.class )	{
    207 				if( _instance == null )	{
    208 					_instance = new FontManager();
    209 					_instance.initialize();
    210 				}
    211 			}
    212 		}
    213 		return _instance;
    214 	}
    215 }