Typeface.java revision 3660789f06c5fbcb81e6c7c79612048bff8f0f66
1/* 2 * Copyright (C) 2006 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package android.graphics; 18 19import android.content.res.AssetManager; 20import android.graphics.FontListParser.Family; 21import android.util.Log; 22import android.util.LongSparseArray; 23import android.util.SparseArray; 24 25import org.xmlpull.v1.XmlPullParserException; 26 27import java.io.File; 28import java.io.FileInputStream; 29import java.io.FileNotFoundException; 30import java.io.IOException; 31import java.util.ArrayList; 32import java.util.HashMap; 33import java.util.List; 34import java.util.Map; 35 36/** 37 * The Typeface class specifies the typeface and intrinsic style of a font. 38 * This is used in the paint, along with optionally Paint settings like 39 * textSize, textSkewX, textScaleX to specify 40 * how text appears when drawn (and measured). 41 */ 42public class Typeface { 43 44 private static String TAG = "Typeface"; 45 46 /** The default NORMAL typeface object */ 47 public static final Typeface DEFAULT; 48 /** 49 * The default BOLD typeface object. Note: this may be not actually be 50 * bold, depending on what fonts are installed. Call getStyle() to know 51 * for sure. 52 */ 53 public static final Typeface DEFAULT_BOLD; 54 /** The NORMAL style of the default sans serif typeface. */ 55 public static final Typeface SANS_SERIF; 56 /** The NORMAL style of the default serif typeface. */ 57 public static final Typeface SERIF; 58 /** The NORMAL style of the default monospace typeface. */ 59 public static final Typeface MONOSPACE; 60 61 static Typeface[] sDefaults; 62 private static final LongSparseArray<SparseArray<Typeface>> sTypefaceCache = 63 new LongSparseArray<SparseArray<Typeface>>(3); 64 65 static Typeface sDefaultTypeface; 66 static Map<String, Typeface> sSystemFontMap; 67 static FontFamily[] sFallbackFonts; 68 69 static final String SYSTEM_FONTS_CONFIG = "system_fonts.xml"; 70 static final String FALLBACK_FONTS_CONFIG = "fallback_fonts.xml"; 71 72 /** 73 * @hide 74 */ 75 public long native_instance; 76 77 // Style 78 public static final int NORMAL = 0; 79 public static final int BOLD = 1; 80 public static final int ITALIC = 2; 81 public static final int BOLD_ITALIC = 3; 82 83 private int mStyle = 0; 84 85 private static void setDefault(Typeface t) { 86 sDefaultTypeface = t; 87 nativeSetDefault(t.native_instance); 88 } 89 90 /** Returns the typeface's intrinsic style attributes */ 91 public int getStyle() { 92 return mStyle; 93 } 94 95 /** Returns true if getStyle() has the BOLD bit set. */ 96 public final boolean isBold() { 97 return (mStyle & BOLD) != 0; 98 } 99 100 /** Returns true if getStyle() has the ITALIC bit set. */ 101 public final boolean isItalic() { 102 return (mStyle & ITALIC) != 0; 103 } 104 105 /** 106 * Create a typeface object given a family name, and option style information. 107 * If null is passed for the name, then the "default" font will be chosen. 108 * The resulting typeface object can be queried (getStyle()) to discover what 109 * its "real" style characteristics are. 110 * 111 * @param familyName May be null. The name of the font family. 112 * @param style The style (normal, bold, italic) of the typeface. 113 * e.g. NORMAL, BOLD, ITALIC, BOLD_ITALIC 114 * @return The best matching typeface. 115 */ 116 public static Typeface create(String familyName, int style) { 117 if (sSystemFontMap != null) { 118 return create(sSystemFontMap.get(familyName), style); 119 } 120 return null; 121 } 122 123 /** 124 * Create a typeface object that best matches the specified existing 125 * typeface and the specified Style. Use this call if you want to pick a new 126 * style from the same family of an existing typeface object. If family is 127 * null, this selects from the default font's family. 128 * 129 * @param family May be null. The name of the existing type face. 130 * @param style The style (normal, bold, italic) of the typeface. 131 * e.g. NORMAL, BOLD, ITALIC, BOLD_ITALIC 132 * @return The best matching typeface. 133 */ 134 public static Typeface create(Typeface family, int style) { 135 long ni = 0; 136 if (family != null) { 137 // Return early if we're asked for the same face/style 138 if (family.mStyle == style) { 139 return family; 140 } 141 142 ni = family.native_instance; 143 } 144 145 Typeface typeface; 146 SparseArray<Typeface> styles = sTypefaceCache.get(ni); 147 148 if (styles != null) { 149 typeface = styles.get(style); 150 if (typeface != null) { 151 return typeface; 152 } 153 } 154 155 typeface = new Typeface(nativeCreateFromTypeface(ni, style)); 156 if (styles == null) { 157 styles = new SparseArray<Typeface>(4); 158 sTypefaceCache.put(ni, styles); 159 } 160 styles.put(style, typeface); 161 162 return typeface; 163 } 164 165 /** 166 * Returns one of the default typeface objects, based on the specified style 167 * 168 * @return the default typeface that corresponds to the style 169 */ 170 public static Typeface defaultFromStyle(int style) { 171 return sDefaults[style]; 172 } 173 174 /** 175 * Create a new typeface from the specified font data. 176 * @param mgr The application's asset manager 177 * @param path The file name of the font data in the assets directory 178 * @return The new typeface. 179 */ 180 public static Typeface createFromAsset(AssetManager mgr, String path) { 181 if (sFallbackFonts != null) { 182 FontFamily fontFamily = new FontFamily(); 183 if (fontFamily.addFontFromAsset(mgr, path)) { 184 FontFamily[] families = { fontFamily }; 185 return createFromFamiliesWithDefault(families); 186 } 187 } 188 return null; 189 } 190 191 /** 192 * Create a new typeface from the specified font file. 193 * 194 * @param path The path to the font data. 195 * @return The new typeface. 196 */ 197 public static Typeface createFromFile(File path) { 198 return createFromFile(path.getAbsolutePath()); 199 } 200 201 /** 202 * Create a new typeface from the specified font file. 203 * 204 * @param path The full path to the font data. 205 * @return The new typeface. 206 */ 207 public static Typeface createFromFile(String path) { 208 if (sFallbackFonts != null) { 209 FontFamily fontFamily = new FontFamily(); 210 if (fontFamily.addFont(path)) { 211 FontFamily[] families = { fontFamily }; 212 return createFromFamiliesWithDefault(families); 213 } 214 } 215 return null; 216 } 217 218 /** 219 * Create a new typeface from an array of font families. 220 * 221 * @param families array of font families 222 * @hide 223 */ 224 public static Typeface createFromFamilies(FontFamily[] families) { 225 long[] ptrArray = new long[families.length]; 226 for (int i = 0; i < families.length; i++) { 227 ptrArray[i] = families[i].mNativePtr; 228 } 229 return new Typeface(nativeCreateFromArray(ptrArray)); 230 } 231 232 /** 233 * Create a new typeface from an array of font families, including 234 * also the font families in the fallback list. 235 * 236 * @param families array of font families 237 * @hide 238 */ 239 public static Typeface createFromFamiliesWithDefault(FontFamily[] families) { 240 long[] ptrArray = new long[families.length + sFallbackFonts.length]; 241 for (int i = 0; i < families.length; i++) { 242 ptrArray[i] = families[i].mNativePtr; 243 } 244 for (int i = 0; i < sFallbackFonts.length; i++) { 245 ptrArray[i + families.length] = sFallbackFonts[i].mNativePtr; 246 } 247 return new Typeface(nativeCreateFromArray(ptrArray)); 248 } 249 250 // don't allow clients to call this directly 251 private Typeface(long ni) { 252 if (ni == 0) { 253 throw new RuntimeException("native typeface cannot be made"); 254 } 255 256 native_instance = ni; 257 mStyle = nativeGetStyle(ni); 258 } 259 260 private static FontFamily makeFamilyFromParsed(FontListParser.Family family) { 261 // TODO: expand to handle attributes like lang and variant 262 FontFamily fontFamily = new FontFamily(family.lang, family.variant); 263 for (String fontFile : family.fontFiles) { 264 fontFamily.addFont(fontFile); 265 } 266 return fontFamily; 267 } 268 269 /* 270 * (non-Javadoc) 271 * 272 * This should only be called once, from the static class initializer block. 273 */ 274 private static void init() { 275 // Load font config and initialize Minikin state 276 File systemFontConfigLocation = getSystemFontConfigLocation(); 277 File systemConfigFilename = new File(systemFontConfigLocation, SYSTEM_FONTS_CONFIG); 278 File configFilename = new File(systemFontConfigLocation, FALLBACK_FONTS_CONFIG); 279 try { 280 // TODO: throws an exception non-Minikin builds, to fail early; 281 // remove when Minikin-only 282 new FontFamily(); 283 284 FileInputStream systemIn = new FileInputStream(systemConfigFilename); 285 List<FontListParser.Family> systemFontConfig = FontListParser.parse(systemIn); 286 287 FileInputStream fallbackIn = new FileInputStream(configFilename); 288 List<FontFamily> familyList = new ArrayList<FontFamily>(); 289 // Note that the default typeface is always present in the fallback list; 290 // this is an enhancement from pre-Minikin behavior. 291 familyList.add(makeFamilyFromParsed(systemFontConfig.get(0))); 292 for (Family f : FontListParser.parse(fallbackIn)) { 293 familyList.add(makeFamilyFromParsed(f)); 294 } 295 sFallbackFonts = familyList.toArray(new FontFamily[familyList.size()]); 296 setDefault(Typeface.createFromFamilies(sFallbackFonts)); 297 298 Map<String, Typeface> systemFonts = new HashMap<String, Typeface>(); 299 for (int i = 0; i < systemFontConfig.size(); i++) { 300 Typeface typeface; 301 Family f = systemFontConfig.get(i); 302 if (i == 0) { 303 // The first entry is the default typeface; no sense in duplicating 304 // the corresponding FontFamily. 305 typeface = sDefaultTypeface; 306 } else { 307 FontFamily fontFamily = makeFamilyFromParsed(f); 308 FontFamily[] families = { fontFamily }; 309 typeface = Typeface.createFromFamiliesWithDefault(families); 310 } 311 for (String name : f.names) { 312 systemFonts.put(name, typeface); 313 } 314 } 315 sSystemFontMap = systemFonts; 316 317 } catch (RuntimeException e) { 318 Log.w(TAG, "Didn't create default family (most likely, non-Minikin build)"); 319 // TODO: normal in non-Minikin case, remove or make error when Minikin-only 320 } catch (FileNotFoundException e) { 321 Log.e(TAG, "Error opening " + configFilename); 322 } catch (IOException e) { 323 Log.e(TAG, "Error reading " + configFilename); 324 } catch (XmlPullParserException e) { 325 Log.e(TAG, "XML parse exception for " + configFilename); 326 } 327 } 328 329 static { 330 init(); 331 // Set up defaults and typefaces exposed in public API 332 DEFAULT = create((String) null, 0); 333 DEFAULT_BOLD = create((String) null, Typeface.BOLD); 334 SANS_SERIF = create("sans-serif", 0); 335 SERIF = create("serif", 0); 336 MONOSPACE = create("monospace", 0); 337 338 sDefaults = new Typeface[] { 339 DEFAULT, 340 DEFAULT_BOLD, 341 create((String) null, Typeface.ITALIC), 342 create((String) null, Typeface.BOLD_ITALIC), 343 }; 344 345 } 346 347 private static File getSystemFontConfigLocation() { 348 return new File("/system/etc/"); 349 } 350 351 @Override 352 protected void finalize() throws Throwable { 353 try { 354 nativeUnref(native_instance); 355 } finally { 356 super.finalize(); 357 } 358 } 359 360 @Override 361 public boolean equals(Object o) { 362 if (this == o) return true; 363 if (o == null || getClass() != o.getClass()) return false; 364 365 Typeface typeface = (Typeface) o; 366 367 return mStyle == typeface.mStyle && native_instance == typeface.native_instance; 368 } 369 370 @Override 371 public int hashCode() { 372 /* 373 * Modified method for hashCode with long native_instance derived from 374 * http://developer.android.com/reference/java/lang/Object.html 375 */ 376 int result = 17; 377 result = 31 * result + (int) (native_instance ^ (native_instance >>> 32)); 378 result = 31 * result + mStyle; 379 return result; 380 } 381 382 private static native long nativeCreateFromTypeface(long native_instance, int style); 383 private static native void nativeUnref(long native_instance); 384 private static native int nativeGetStyle(long native_instance); 385 private static native long nativeCreateFromArray(long[] familyArray); 386 private static native void nativeSetDefault(long native_instance); 387} 388