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 }