1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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
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 }