4 * License : The MIT License
5 * Copyright(c) 2009 olyutorskii
8 package jp.sfjp.jindolf.glyph;
11 import java.awt.Rectangle;
12 import java.awt.font.FontRenderContext;
13 import java.awt.font.GlyphVector;
14 import java.awt.geom.AffineTransform;
15 import java.awt.geom.Rectangle2D;
16 import java.text.CharacterIterator;
17 import java.util.Locale;
22 public class FontInfo{
25 public static final FontEnv DEFAULT_FONTENV;
27 public static final FontInfo DEFAULT_FONTINFO;
30 public static final int DEF_SIZE = 16;
31 /** デフォルトのフォントスタイル。 */
32 public static final int DEF_STYLE = 0x00 | Font.PLAIN;
34 /** {@link java.util.Locale#ROOT}代替品。 */
35 private static final Locale LOCALE_ROOT = new Locale("", "", "");
36 /** MSリコー系日本語ベクトルフォント下限ポイントサイズ。 */
37 private static final int MS_VEC_LIMIT = 24;
39 private static final char DQ = '"';
43 DEFAULT_FONTENV = FontEnv.DEFAULT;
44 DEFAULT_FONTINFO = new FontInfo();
48 // いずれのフィールドもnull値はデフォルト値の遅延評価フラグ
49 private String familyName;
51 private FontRenderContext context;
56 * デフォルトフォントとそれに適した描画属性が指定される。
59 this((Font) null, (FontRenderContext) null);
68 public FontInfo(Font font, FontRenderContext context){
70 this.familyName = null;
72 this.context = context;
78 * マイクロソフト&リコー(リョービイマジクス)系
79 * 日本語ベクトルフォントか否か、ファミリ名で見当をつける。
81 * <p>日本語Windows同梱のMSゴシックやMS明朝などが対象。
88 protected static boolean isMsRicohJpFont(Font font){
89 String rootFamilyName = font.getFamily(LOCALE_ROOT);
90 if(rootFamilyName.startsWith("MS")){
91 if(rootFamilyName.contains("Gothic")) return true;
92 if(rootFamilyName.contains("Mincho")) return true;
98 * ビットマップフォントか否か見当をつける。
101 * 実用上、小さめのMSPゴシックを補足できればそれでいい。
104 * アンチエイリアスやサブピクセルを使わないほうが
107 * @param font 判定対象フォント
108 * @return ビットマップフォントらしかったらtrue
110 protected static boolean isBitmapFont(Font font){
111 if(font.getSize() >= MS_VEC_LIMIT) return false;
112 if(isMsRicohJpFont(font)) return true;
117 * フォントに応じた最適な描画設定を生成する。
119 * <p>ビットマップフォントと推測されるときは
120 * アンチエイリアスやサブピクセル補完を無効にする。
125 protected static FontRenderContext createBestContext(Font font){
126 boolean isAntiAliased;
127 boolean usesFractionalMetrics;
129 if(isBitmapFont(font)){
130 isAntiAliased = false;
131 usesFractionalMetrics = false;
133 isAntiAliased = true;
134 usesFractionalMetrics = true;
137 AffineTransform identity = ImtblAffineTx.IDENTITY;
138 FontRenderContext result;
139 result = new FontRenderContext(identity,
141 usesFractionalMetrics );
150 private String getFamilyName(){
151 if(this.familyName == null){
152 if(this.font == null){
153 this.familyName = DEFAULT_FONTENV.selectFontFamily();
156 this.familyName = getRootFamilyName();
159 return this.familyName;
166 public Font getFont(){
167 if(this.font == null){
168 String name = getFamilyName();
169 this.font = new Font(name, DEF_STYLE, DEF_SIZE);
178 public FontRenderContext getFontRenderContext(){
179 if(this.context == null){
180 Font thisFont = getFont();
181 this.context = createBestContext(thisFont);
187 * アンチエイリアス機能を使うか判定する。
188 * @return アンチエイリアス機能を使うならtrue
190 public boolean isAntiAliased(){
191 FontRenderContext frc = getFontRenderContext();
192 boolean result = frc.isAntiAliased();
198 * @return サブピクセル精度を使うならtrue
200 public boolean usesFractionalMetrics(){
201 FontRenderContext frc = getFontRenderContext();
202 boolean result = frc.usesFractionalMetrics();
209 * @see java.awt.Font#getMaxCharBounds(FontRenderContext)
211 public Rectangle getMaxCharBounds(){
212 Font thisFont = getFont();
213 FontRenderContext frc = getFontRenderContext();
214 Rectangle2D r2d = thisFont.getMaxCharBounds(frc);
215 Rectangle rect = r2d.getBounds();
221 * @param newFont 新フォント
224 public FontInfo deriveFont(Font newFont){
225 FontInfo result = new FontInfo(newFont, this.context);
231 * @param newContext 新描画設定
234 public FontInfo deriveRenderContext(FontRenderContext newContext){
235 FontInfo result = new FontInfo(this.font, newContext);
241 * @param isAntiAliases アンチエイリアス設定
242 * @param useFractional サブピクセル精度設定
245 public FontInfo deriveRenderContext(boolean isAntiAliases,
246 boolean useFractional ){
248 if(this.context == null){
249 tx = ImtblAffineTx.IDENTITY;
251 tx = this.context.getTransform();
253 FontRenderContext newContext =
254 new FontRenderContext(tx, isAntiAliases, useFractional);
255 return deriveRenderContext(newContext);
260 * @param iterator 文字列
263 public GlyphVector createGlyphVector(CharacterIterator iterator){
264 Font thisFont = getFont();
265 FontRenderContext frc = getFontRenderContext();
266 GlyphVector glyph = thisFont.createGlyphVector(frc, iterator);
271 * ロケール中立なフォントファミリ名を返す。
274 * @see Font#getFamily(Locale)
276 public String getRootFamilyName(){
277 Font thisFont = getFont();
278 String result = thisFont.getFamily(LOCALE_ROOT);
283 * Font#decode()用の名前を返す。
284 * 空白が含まれる場合は二重引用符で囲まれる。
285 * @return {@link java.awt.Font#decode(String)}用の名前
286 * @see java.awt.Font#decode(String)
288 public String getFontDecodeName(){
289 StringBuilder result = new StringBuilder();
291 String name = getRootFamilyName();
293 Font thisFont = getFont();
294 StringBuilder style = new StringBuilder();
295 if(thisFont.isBold()) style.append("BOLD");
296 if(thisFont.isItalic()) style.append("ITALIC");
297 if(style.length() <= 0) style.append("PLAIN");
299 int fontSize = thisFont.getSize();
302 .append('-').append(style)
303 .append('-').append(fontSize);
305 if( result.indexOf("\u0020") >= 0
306 || result.indexOf("\u3000") >= 0 ){
307 result.insert(0, DQ).append(DQ);
310 return result.toString();
315 * @param obj {@inheritDoc}
316 * @return {@inheritDoc}
319 public boolean equals(Object obj){
320 if( ! (obj instanceof FontInfo) ) return false;
321 FontInfo target = (FontInfo) obj;
323 Font thisFont = getFont();
324 Font targetFont = target.getFont();
325 if( ! (thisFont.equals(targetFont)) ){
329 FontRenderContext thisContext = getFontRenderContext();
330 FontRenderContext targetContext = target.getFontRenderContext();
331 if( ! (thisContext.equals(targetContext)) ){
340 * @return {@inheritDoc}
343 public int hashCode(){
344 int hashFont = getFont().hashCode();
345 int hashContext = getFontRenderContext().hashCode();
346 return hashFont ^ hashContext;