| /* |
| * Copyright (C) 2006 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package android.graphics; |
| |
| import android.content.res.AssetManager; |
| import android.graphics.FontListParser.Family; |
| import android.util.Log; |
| import android.util.LongSparseArray; |
| import android.util.SparseArray; |
| |
| import org.xmlpull.v1.XmlPullParserException; |
| |
| import java.io.File; |
| import java.io.FileInputStream; |
| import java.io.FileNotFoundException; |
| import java.io.IOException; |
| import java.util.ArrayList; |
| import java.util.HashMap; |
| import java.util.List; |
| import java.util.Map; |
| |
| /** |
| * The Typeface class specifies the typeface and intrinsic style of a font. |
| * This is used in the paint, along with optionally Paint settings like |
| * textSize, textSkewX, textScaleX to specify |
| * how text appears when drawn (and measured). |
| */ |
| public class Typeface { |
| |
| private static String TAG = "Typeface"; |
| |
| /** The default NORMAL typeface object */ |
| public static final Typeface DEFAULT; |
| /** |
| * The default BOLD typeface object. Note: this may be not actually be |
| * bold, depending on what fonts are installed. Call getStyle() to know |
| * for sure. |
| */ |
| public static final Typeface DEFAULT_BOLD; |
| /** The NORMAL style of the default sans serif typeface. */ |
| public static final Typeface SANS_SERIF; |
| /** The NORMAL style of the default serif typeface. */ |
| public static final Typeface SERIF; |
| /** The NORMAL style of the default monospace typeface. */ |
| public static final Typeface MONOSPACE; |
| |
| static Typeface[] sDefaults; |
| private static final LongSparseArray<SparseArray<Typeface>> sTypefaceCache = |
| new LongSparseArray<SparseArray<Typeface>>(3); |
| |
| static Typeface sDefaultTypeface; |
| static Map<String, Typeface> sSystemFontMap; |
| static FontFamily[] sFallbackFonts; |
| |
| static final String SYSTEM_FONTS_CONFIG = "system_fonts.xml"; |
| static final String FALLBACK_FONTS_CONFIG = "fallback_fonts.xml"; |
| |
| /** |
| * @hide |
| */ |
| public long native_instance; |
| |
| // Style |
| public static final int NORMAL = 0; |
| public static final int BOLD = 1; |
| public static final int ITALIC = 2; |
| public static final int BOLD_ITALIC = 3; |
| |
| private int mStyle = 0; |
| |
| private static void setDefault(Typeface t) { |
| sDefaultTypeface = t; |
| nativeSetDefault(t.native_instance); |
| } |
| |
| /** Returns the typeface's intrinsic style attributes */ |
| public int getStyle() { |
| return mStyle; |
| } |
| |
| /** Returns true if getStyle() has the BOLD bit set. */ |
| public final boolean isBold() { |
| return (mStyle & BOLD) != 0; |
| } |
| |
| /** Returns true if getStyle() has the ITALIC bit set. */ |
| public final boolean isItalic() { |
| return (mStyle & ITALIC) != 0; |
| } |
| |
| /** |
| * Create a typeface object given a family name, and option style information. |
| * If null is passed for the name, then the "default" font will be chosen. |
| * The resulting typeface object can be queried (getStyle()) to discover what |
| * its "real" style characteristics are. |
| * |
| * @param familyName May be null. The name of the font family. |
| * @param style The style (normal, bold, italic) of the typeface. |
| * e.g. NORMAL, BOLD, ITALIC, BOLD_ITALIC |
| * @return The best matching typeface. |
| */ |
| public static Typeface create(String familyName, int style) { |
| if (sSystemFontMap != null) { |
| return create(sSystemFontMap.get(familyName), style); |
| } |
| return null; |
| } |
| |
| /** |
| * Create a typeface object that best matches the specified existing |
| * typeface and the specified Style. Use this call if you want to pick a new |
| * style from the same family of an existing typeface object. If family is |
| * null, this selects from the default font's family. |
| * |
| * @param family May be null. The name of the existing type face. |
| * @param style The style (normal, bold, italic) of the typeface. |
| * e.g. NORMAL, BOLD, ITALIC, BOLD_ITALIC |
| * @return The best matching typeface. |
| */ |
| public static Typeface create(Typeface family, int style) { |
| long ni = 0; |
| if (family != null) { |
| // Return early if we're asked for the same face/style |
| if (family.mStyle == style) { |
| return family; |
| } |
| |
| ni = family.native_instance; |
| } |
| |
| Typeface typeface; |
| SparseArray<Typeface> styles = sTypefaceCache.get(ni); |
| |
| if (styles != null) { |
| typeface = styles.get(style); |
| if (typeface != null) { |
| return typeface; |
| } |
| } |
| |
| typeface = new Typeface(nativeCreateFromTypeface(ni, style)); |
| if (styles == null) { |
| styles = new SparseArray<Typeface>(4); |
| sTypefaceCache.put(ni, styles); |
| } |
| styles.put(style, typeface); |
| |
| return typeface; |
| } |
| |
| /** |
| * Returns one of the default typeface objects, based on the specified style |
| * |
| * @return the default typeface that corresponds to the style |
| */ |
| public static Typeface defaultFromStyle(int style) { |
| return sDefaults[style]; |
| } |
| |
| /** |
| * Create a new typeface from the specified font data. |
| * @param mgr The application's asset manager |
| * @param path The file name of the font data in the assets directory |
| * @return The new typeface. |
| */ |
| public static Typeface createFromAsset(AssetManager mgr, String path) { |
| if (sFallbackFonts != null) { |
| FontFamily fontFamily = new FontFamily(); |
| if (fontFamily.addFontFromAsset(mgr, path)) { |
| FontFamily[] families = { fontFamily }; |
| return createFromFamiliesWithDefault(families); |
| } |
| } |
| return null; |
| } |
| |
| /** |
| * Create a new typeface from the specified font file. |
| * |
| * @param path The path to the font data. |
| * @return The new typeface. |
| */ |
| public static Typeface createFromFile(File path) { |
| return createFromFile(path.getAbsolutePath()); |
| } |
| |
| /** |
| * Create a new typeface from the specified font file. |
| * |
| * @param path The full path to the font data. |
| * @return The new typeface. |
| */ |
| public static Typeface createFromFile(String path) { |
| if (sFallbackFonts != null) { |
| FontFamily fontFamily = new FontFamily(); |
| if (fontFamily.addFont(path)) { |
| FontFamily[] families = { fontFamily }; |
| return createFromFamiliesWithDefault(families); |
| } |
| } |
| return null; |
| } |
| |
| /** |
| * Create a new typeface from an array of font families. |
| * |
| * @param families array of font families |
| * @hide |
| */ |
| public static Typeface createFromFamilies(FontFamily[] families) { |
| long[] ptrArray = new long[families.length]; |
| for (int i = 0; i < families.length; i++) { |
| ptrArray[i] = families[i].mNativePtr; |
| } |
| return new Typeface(nativeCreateFromArray(ptrArray)); |
| } |
| |
| /** |
| * Create a new typeface from an array of font families, including |
| * also the font families in the fallback list. |
| * |
| * @param families array of font families |
| * @hide |
| */ |
| public static Typeface createFromFamiliesWithDefault(FontFamily[] families) { |
| long[] ptrArray = new long[families.length + sFallbackFonts.length]; |
| for (int i = 0; i < families.length; i++) { |
| ptrArray[i] = families[i].mNativePtr; |
| } |
| for (int i = 0; i < sFallbackFonts.length; i++) { |
| ptrArray[i + families.length] = sFallbackFonts[i].mNativePtr; |
| } |
| return new Typeface(nativeCreateFromArray(ptrArray)); |
| } |
| |
| // don't allow clients to call this directly |
| private Typeface(long ni) { |
| if (ni == 0) { |
| throw new RuntimeException("native typeface cannot be made"); |
| } |
| |
| native_instance = ni; |
| mStyle = nativeGetStyle(ni); |
| } |
| |
| private static FontFamily makeFamilyFromParsed(FontListParser.Family family) { |
| // TODO: expand to handle attributes like lang and variant |
| FontFamily fontFamily = new FontFamily(family.lang, family.variant); |
| for (String fontFile : family.fontFiles) { |
| fontFamily.addFont(fontFile); |
| } |
| return fontFamily; |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * This should only be called once, from the static class initializer block. |
| */ |
| private static void init() { |
| // Load font config and initialize Minikin state |
| File systemFontConfigLocation = getSystemFontConfigLocation(); |
| File systemConfigFilename = new File(systemFontConfigLocation, SYSTEM_FONTS_CONFIG); |
| File configFilename = new File(systemFontConfigLocation, FALLBACK_FONTS_CONFIG); |
| try { |
| // TODO: throws an exception non-Minikin builds, to fail early; |
| // remove when Minikin-only |
| new FontFamily(); |
| |
| FileInputStream systemIn = new FileInputStream(systemConfigFilename); |
| List<FontListParser.Family> systemFontConfig = FontListParser.parse(systemIn); |
| |
| FileInputStream fallbackIn = new FileInputStream(configFilename); |
| List<FontFamily> familyList = new ArrayList<FontFamily>(); |
| // Note that the default typeface is always present in the fallback list; |
| // this is an enhancement from pre-Minikin behavior. |
| familyList.add(makeFamilyFromParsed(systemFontConfig.get(0))); |
| for (Family f : FontListParser.parse(fallbackIn)) { |
| familyList.add(makeFamilyFromParsed(f)); |
| } |
| sFallbackFonts = familyList.toArray(new FontFamily[familyList.size()]); |
| setDefault(Typeface.createFromFamilies(sFallbackFonts)); |
| |
| Map<String, Typeface> systemFonts = new HashMap<String, Typeface>(); |
| for (int i = 0; i < systemFontConfig.size(); i++) { |
| Typeface typeface; |
| Family f = systemFontConfig.get(i); |
| if (i == 0) { |
| // The first entry is the default typeface; no sense in duplicating |
| // the corresponding FontFamily. |
| typeface = sDefaultTypeface; |
| } else { |
| FontFamily fontFamily = makeFamilyFromParsed(f); |
| FontFamily[] families = { fontFamily }; |
| typeface = Typeface.createFromFamiliesWithDefault(families); |
| } |
| for (String name : f.names) { |
| systemFonts.put(name, typeface); |
| } |
| } |
| sSystemFontMap = systemFonts; |
| |
| } catch (RuntimeException e) { |
| Log.w(TAG, "Didn't create default family (most likely, non-Minikin build)"); |
| // TODO: normal in non-Minikin case, remove or make error when Minikin-only |
| } catch (FileNotFoundException e) { |
| Log.e(TAG, "Error opening " + configFilename); |
| } catch (IOException e) { |
| Log.e(TAG, "Error reading " + configFilename); |
| } catch (XmlPullParserException e) { |
| Log.e(TAG, "XML parse exception for " + configFilename); |
| } |
| } |
| |
| static { |
| init(); |
| // Set up defaults and typefaces exposed in public API |
| DEFAULT = create((String) null, 0); |
| DEFAULT_BOLD = create((String) null, Typeface.BOLD); |
| SANS_SERIF = create("sans-serif", 0); |
| SERIF = create("serif", 0); |
| MONOSPACE = create("monospace", 0); |
| |
| sDefaults = new Typeface[] { |
| DEFAULT, |
| DEFAULT_BOLD, |
| create((String) null, Typeface.ITALIC), |
| create((String) null, Typeface.BOLD_ITALIC), |
| }; |
| |
| } |
| |
| private static File getSystemFontConfigLocation() { |
| return new File("/system/etc/"); |
| } |
| |
| @Override |
| protected void finalize() throws Throwable { |
| try { |
| nativeUnref(native_instance); |
| } finally { |
| super.finalize(); |
| } |
| } |
| |
| @Override |
| public boolean equals(Object o) { |
| if (this == o) return true; |
| if (o == null || getClass() != o.getClass()) return false; |
| |
| Typeface typeface = (Typeface) o; |
| |
| return mStyle == typeface.mStyle && native_instance == typeface.native_instance; |
| } |
| |
| @Override |
| public int hashCode() { |
| /* |
| * Modified method for hashCode with long native_instance derived from |
| * http://developer.android.com/reference/java/lang/Object.html |
| */ |
| int result = 17; |
| result = 31 * result + (int) (native_instance ^ (native_instance >>> 32)); |
| result = 31 * result + mStyle; |
| return result; |
| } |
| |
| private static native long nativeCreateFromTypeface(long native_instance, int style); |
| private static native void nativeUnref(long native_instance); |
| private static native int nativeGetStyle(long native_instance); |
| private static native long nativeCreateFromArray(long[] familyArray); |
| private static native void nativeSetDefault(long native_instance); |
| } |