Typeface.java revision 3660789f06c5fbcb81e6c7c79612048bff8f0f66
19066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/*
29066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Copyright (C) 2006 The Android Open Source Project
39066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
49066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License");
59066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * you may not use this file except in compliance with the License.
69066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * You may obtain a copy of the License at
79066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
89066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *      http://www.apache.org/licenses/LICENSE-2.0
99066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Unless required by applicable law or agreed to in writing, software
119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS,
129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * See the License for the specific language governing permissions and
149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * limitations under the License.
159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpackage android.graphics;
189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.res.AssetManager;
209a5b61ccc83303ceeec2059f58c1977af9faa9e3Raph Levienimport android.graphics.FontListParser.Family;
211a73f732f91e97c9c66b808c245ddda36a10e987Raph Levienimport android.util.Log;
2236bef0bf30d6bae48cf3837df351075ca4fce654Ashok Bhatimport android.util.LongSparseArray;
239a5b61ccc83303ceeec2059f58c1977af9faa9e3Raph Levienimport android.util.SparseArray;
249a5b61ccc83303ceeec2059f58c1977af9faa9e3Raph Levien
259a5b61ccc83303ceeec2059f58c1977af9faa9e3Raph Levienimport org.xmlpull.v1.XmlPullParserException;
269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
27a87a132ebf1c2dd733cf52feff6e44525257c961Romain Guyimport java.io.File;
289a5b61ccc83303ceeec2059f58c1977af9faa9e3Raph Levienimport java.io.FileInputStream;
299a5b61ccc83303ceeec2059f58c1977af9faa9e3Raph Levienimport java.io.FileNotFoundException;
309a5b61ccc83303ceeec2059f58c1977af9faa9e3Raph Levienimport java.io.IOException;
319a5b61ccc83303ceeec2059f58c1977af9faa9e3Raph Levienimport java.util.ArrayList;
329a5b61ccc83303ceeec2059f58c1977af9faa9e3Raph Levienimport java.util.HashMap;
339a5b61ccc83303ceeec2059f58c1977af9faa9e3Raph Levienimport java.util.List;
349a5b61ccc83303ceeec2059f58c1977af9faa9e3Raph Levienimport java.util.Map;
35a87a132ebf1c2dd733cf52feff6e44525257c961Romain Guy
369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/**
379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * The Typeface class specifies the typeface and intrinsic style of a font.
389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * This is used in the paint, along with optionally Paint settings like
399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * textSize, textSkewX, textScaleX to specify
409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * how text appears when drawn (and measured).
419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpublic class Typeface {
439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
449a5b61ccc83303ceeec2059f58c1977af9faa9e3Raph Levien    private static String TAG = "Typeface";
459a5b61ccc83303ceeec2059f58c1977af9faa9e3Raph Levien
469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** The default NORMAL typeface object */
479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static final Typeface DEFAULT;
489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * The default BOLD typeface object. Note: this may be not actually be
509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * bold, depending on what fonts are installed. Call getStyle() to know
519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * for sure.
529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static final Typeface DEFAULT_BOLD;
549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** The NORMAL style of the default sans serif typeface. */
559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static final Typeface SANS_SERIF;
569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** The NORMAL style of the default serif typeface. */
579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static final Typeface SERIF;
589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** The NORMAL style of the default monospace typeface. */
599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static final Typeface MONOSPACE;
609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6146926698996d3857a650ed535024a88dbeaff1e1Romain Guy    static Typeface[] sDefaults;
6236bef0bf30d6bae48cf3837df351075ca4fce654Ashok Bhat    private static final LongSparseArray<SparseArray<Typeface>> sTypefaceCache =
6336bef0bf30d6bae48cf3837df351075ca4fce654Ashok Bhat            new LongSparseArray<SparseArray<Typeface>>(3);
6446926698996d3857a650ed535024a88dbeaff1e1Romain Guy
659a5b61ccc83303ceeec2059f58c1977af9faa9e3Raph Levien    static Typeface sDefaultTypeface;
669a5b61ccc83303ceeec2059f58c1977af9faa9e3Raph Levien    static Map<String, Typeface> sSystemFontMap;
67363e21b4518d7059638df2821b8a0947f74eaf2cRaph Levien    static FontFamily[] sFallbackFonts;
689a5b61ccc83303ceeec2059f58c1977af9faa9e3Raph Levien
69baef8c1ffe5c900fb0da9512654bf249b5fc9269Deepanshu Gupta    static final String SYSTEM_FONTS_CONFIG = "system_fonts.xml";
70baef8c1ffe5c900fb0da9512654bf249b5fc9269Deepanshu Gupta    static final String FALLBACK_FONTS_CONFIG = "fallback_fonts.xml";
71baef8c1ffe5c900fb0da9512654bf249b5fc9269Deepanshu Gupta
72a033630e805c407080221e20b236b6054f324670Raph Levien    /**
73a033630e805c407080221e20b236b6054f324670Raph Levien     * @hide
74a033630e805c407080221e20b236b6054f324670Raph Levien     */
7536bef0bf30d6bae48cf3837df351075ca4fce654Ashok Bhat    public long native_instance;
769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // Style
789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static final int NORMAL = 0;
799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static final int BOLD = 1;
809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static final int ITALIC = 2;
819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static final int BOLD_ITALIC = 3;
829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8346926698996d3857a650ed535024a88dbeaff1e1Romain Guy    private int mStyle = 0;
8446926698996d3857a650ed535024a88dbeaff1e1Romain Guy
859a5b61ccc83303ceeec2059f58c1977af9faa9e3Raph Levien    private static void setDefault(Typeface t) {
869a5b61ccc83303ceeec2059f58c1977af9faa9e3Raph Levien        sDefaultTypeface = t;
879a5b61ccc83303ceeec2059f58c1977af9faa9e3Raph Levien        nativeSetDefault(t.native_instance);
889a5b61ccc83303ceeec2059f58c1977af9faa9e3Raph Levien    }
899a5b61ccc83303ceeec2059f58c1977af9faa9e3Raph Levien
909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** Returns the typeface's intrinsic style attributes */
919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public int getStyle() {
9246926698996d3857a650ed535024a88dbeaff1e1Romain Guy        return mStyle;
939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** Returns true if getStyle() has the BOLD bit set. */
969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public final boolean isBold() {
9746926698996d3857a650ed535024a88dbeaff1e1Romain Guy        return (mStyle & BOLD) != 0;
989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** Returns true if getStyle() has the ITALIC bit set. */
1019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public final boolean isItalic() {
10246926698996d3857a650ed535024a88dbeaff1e1Romain Guy        return (mStyle & ITALIC) != 0;
1039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
1069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Create a typeface object given a family name, and option style information.
1079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * If null is passed for the name, then the "default" font will be chosen.
1089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * The resulting typeface object can be queried (getStyle()) to discover what
1099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * its "real" style characteristics are.
1109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
1119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param familyName May be null. The name of the font family.
1129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param style  The style (normal, bold, italic) of the typeface.
1139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *               e.g. NORMAL, BOLD, ITALIC, BOLD_ITALIC
1149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return The best matching typeface.
1159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
1169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static Typeface create(String familyName, int style) {
1179a5b61ccc83303ceeec2059f58c1977af9faa9e3Raph Levien        if (sSystemFontMap != null) {
1189a5b61ccc83303ceeec2059f58c1977af9faa9e3Raph Levien            return create(sSystemFontMap.get(familyName), style);
1199a5b61ccc83303ceeec2059f58c1977af9faa9e3Raph Levien        }
1203660789f06c5fbcb81e6c7c79612048bff8f0f66Raph Levien        return null;
1219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
1249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Create a typeface object that best matches the specified existing
1259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * typeface and the specified Style. Use this call if you want to pick a new
1269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * style from the same family of an existing typeface object. If family is
1279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * null, this selects from the default font's family.
1289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
1299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param family May be null. The name of the existing type face.
1309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param style  The style (normal, bold, italic) of the typeface.
1319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *               e.g. NORMAL, BOLD, ITALIC, BOLD_ITALIC
1329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return The best matching typeface.
1339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
1349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static Typeface create(Typeface family, int style) {
13536bef0bf30d6bae48cf3837df351075ca4fce654Ashok Bhat        long ni = 0;
1369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (family != null) {
13746926698996d3857a650ed535024a88dbeaff1e1Romain Guy            // Return early if we're asked for the same face/style
13846926698996d3857a650ed535024a88dbeaff1e1Romain Guy            if (family.mStyle == style) {
13946926698996d3857a650ed535024a88dbeaff1e1Romain Guy                return family;
14046926698996d3857a650ed535024a88dbeaff1e1Romain Guy            }
14146926698996d3857a650ed535024a88dbeaff1e1Romain Guy
1429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            ni = family.native_instance;
1439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
14446926698996d3857a650ed535024a88dbeaff1e1Romain Guy
14546926698996d3857a650ed535024a88dbeaff1e1Romain Guy        Typeface typeface;
14646926698996d3857a650ed535024a88dbeaff1e1Romain Guy        SparseArray<Typeface> styles = sTypefaceCache.get(ni);
14746926698996d3857a650ed535024a88dbeaff1e1Romain Guy
14846926698996d3857a650ed535024a88dbeaff1e1Romain Guy        if (styles != null) {
14946926698996d3857a650ed535024a88dbeaff1e1Romain Guy            typeface = styles.get(style);
15046926698996d3857a650ed535024a88dbeaff1e1Romain Guy            if (typeface != null) {
15146926698996d3857a650ed535024a88dbeaff1e1Romain Guy                return typeface;
15246926698996d3857a650ed535024a88dbeaff1e1Romain Guy            }
15346926698996d3857a650ed535024a88dbeaff1e1Romain Guy        }
15446926698996d3857a650ed535024a88dbeaff1e1Romain Guy
15546926698996d3857a650ed535024a88dbeaff1e1Romain Guy        typeface = new Typeface(nativeCreateFromTypeface(ni, style));
15646926698996d3857a650ed535024a88dbeaff1e1Romain Guy        if (styles == null) {
15746926698996d3857a650ed535024a88dbeaff1e1Romain Guy            styles = new SparseArray<Typeface>(4);
15846926698996d3857a650ed535024a88dbeaff1e1Romain Guy            sTypefaceCache.put(ni, styles);
15946926698996d3857a650ed535024a88dbeaff1e1Romain Guy        }
16046926698996d3857a650ed535024a88dbeaff1e1Romain Guy        styles.put(style, typeface);
16146926698996d3857a650ed535024a88dbeaff1e1Romain Guy
16246926698996d3857a650ed535024a88dbeaff1e1Romain Guy        return typeface;
1639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
1669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Returns one of the default typeface objects, based on the specified style
1679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
1689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return the default typeface that corresponds to the style
1699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
1709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static Typeface defaultFromStyle(int style) {
1719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return sDefaults[style];
1729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1739a5b61ccc83303ceeec2059f58c1977af9faa9e3Raph Levien
1749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
1759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Create a new typeface from the specified font data.
1769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param mgr The application's asset manager
1779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param path  The file name of the font data in the assets directory
1789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return The new typeface.
1799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
1809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static Typeface createFromAsset(AssetManager mgr, String path) {
181d573794d83a049fe59e289944f0cd77406dd776aRaph Levien        if (sFallbackFonts != null) {
182d573794d83a049fe59e289944f0cd77406dd776aRaph Levien            FontFamily fontFamily = new FontFamily();
183d573794d83a049fe59e289944f0cd77406dd776aRaph Levien            if (fontFamily.addFontFromAsset(mgr, path)) {
184d573794d83a049fe59e289944f0cd77406dd776aRaph Levien                FontFamily[] families = { fontFamily };
185d573794d83a049fe59e289944f0cd77406dd776aRaph Levien                return createFromFamiliesWithDefault(families);
186d573794d83a049fe59e289944f0cd77406dd776aRaph Levien            }
187d573794d83a049fe59e289944f0cd77406dd776aRaph Levien        }
1883660789f06c5fbcb81e6c7c79612048bff8f0f66Raph Levien        return null;
1899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
190a87a132ebf1c2dd733cf52feff6e44525257c961Romain Guy
191a87a132ebf1c2dd733cf52feff6e44525257c961Romain Guy    /**
192a87a132ebf1c2dd733cf52feff6e44525257c961Romain Guy     * Create a new typeface from the specified font file.
193a87a132ebf1c2dd733cf52feff6e44525257c961Romain Guy     *
1949a5b61ccc83303ceeec2059f58c1977af9faa9e3Raph Levien     * @param path The path to the font data.
195a87a132ebf1c2dd733cf52feff6e44525257c961Romain Guy     * @return The new typeface.
196a87a132ebf1c2dd733cf52feff6e44525257c961Romain Guy     */
197a87a132ebf1c2dd733cf52feff6e44525257c961Romain Guy    public static Typeface createFromFile(File path) {
198d573794d83a049fe59e289944f0cd77406dd776aRaph Levien        return createFromFile(path.getAbsolutePath());
199a87a132ebf1c2dd733cf52feff6e44525257c961Romain Guy    }
200a87a132ebf1c2dd733cf52feff6e44525257c961Romain Guy
201a87a132ebf1c2dd733cf52feff6e44525257c961Romain Guy    /**
202a87a132ebf1c2dd733cf52feff6e44525257c961Romain Guy     * Create a new typeface from the specified font file.
203a87a132ebf1c2dd733cf52feff6e44525257c961Romain Guy     *
2049a5b61ccc83303ceeec2059f58c1977af9faa9e3Raph Levien     * @param path The full path to the font data.
205a87a132ebf1c2dd733cf52feff6e44525257c961Romain Guy     * @return The new typeface.
206a87a132ebf1c2dd733cf52feff6e44525257c961Romain Guy     */
207a87a132ebf1c2dd733cf52feff6e44525257c961Romain Guy    public static Typeface createFromFile(String path) {
208d573794d83a049fe59e289944f0cd77406dd776aRaph Levien        if (sFallbackFonts != null) {
209d573794d83a049fe59e289944f0cd77406dd776aRaph Levien            FontFamily fontFamily = new FontFamily();
210d573794d83a049fe59e289944f0cd77406dd776aRaph Levien            if (fontFamily.addFont(path)) {
211d573794d83a049fe59e289944f0cd77406dd776aRaph Levien                FontFamily[] families = { fontFamily };
212d573794d83a049fe59e289944f0cd77406dd776aRaph Levien                return createFromFamiliesWithDefault(families);
213d573794d83a049fe59e289944f0cd77406dd776aRaph Levien            }
214d573794d83a049fe59e289944f0cd77406dd776aRaph Levien        }
2153660789f06c5fbcb81e6c7c79612048bff8f0f66Raph Levien        return null;
216a87a132ebf1c2dd733cf52feff6e44525257c961Romain Guy    }
217a87a132ebf1c2dd733cf52feff6e44525257c961Romain Guy
2181a73f732f91e97c9c66b808c245ddda36a10e987Raph Levien    /**
2191a73f732f91e97c9c66b808c245ddda36a10e987Raph Levien     * Create a new typeface from an array of font families.
2201a73f732f91e97c9c66b808c245ddda36a10e987Raph Levien     *
2211a73f732f91e97c9c66b808c245ddda36a10e987Raph Levien     * @param families array of font families
2221a73f732f91e97c9c66b808c245ddda36a10e987Raph Levien     * @hide
2231a73f732f91e97c9c66b808c245ddda36a10e987Raph Levien     */
2241a73f732f91e97c9c66b808c245ddda36a10e987Raph Levien    public static Typeface createFromFamilies(FontFamily[] families) {
2251a73f732f91e97c9c66b808c245ddda36a10e987Raph Levien        long[] ptrArray = new long[families.length];
2261a73f732f91e97c9c66b808c245ddda36a10e987Raph Levien        for (int i = 0; i < families.length; i++) {
2271a73f732f91e97c9c66b808c245ddda36a10e987Raph Levien            ptrArray[i] = families[i].mNativePtr;
2281a73f732f91e97c9c66b808c245ddda36a10e987Raph Levien        }
2291a73f732f91e97c9c66b808c245ddda36a10e987Raph Levien        return new Typeface(nativeCreateFromArray(ptrArray));
2301a73f732f91e97c9c66b808c245ddda36a10e987Raph Levien    }
2311a73f732f91e97c9c66b808c245ddda36a10e987Raph Levien
232363e21b4518d7059638df2821b8a0947f74eaf2cRaph Levien    /**
233363e21b4518d7059638df2821b8a0947f74eaf2cRaph Levien     * Create a new typeface from an array of font families, including
234363e21b4518d7059638df2821b8a0947f74eaf2cRaph Levien     * also the font families in the fallback list.
235363e21b4518d7059638df2821b8a0947f74eaf2cRaph Levien     *
236363e21b4518d7059638df2821b8a0947f74eaf2cRaph Levien     * @param families array of font families
237363e21b4518d7059638df2821b8a0947f74eaf2cRaph Levien     * @hide
238363e21b4518d7059638df2821b8a0947f74eaf2cRaph Levien     */
239363e21b4518d7059638df2821b8a0947f74eaf2cRaph Levien    public static Typeface createFromFamiliesWithDefault(FontFamily[] families) {
240363e21b4518d7059638df2821b8a0947f74eaf2cRaph Levien        long[] ptrArray = new long[families.length + sFallbackFonts.length];
241363e21b4518d7059638df2821b8a0947f74eaf2cRaph Levien        for (int i = 0; i < families.length; i++) {
242363e21b4518d7059638df2821b8a0947f74eaf2cRaph Levien            ptrArray[i] = families[i].mNativePtr;
243363e21b4518d7059638df2821b8a0947f74eaf2cRaph Levien        }
244363e21b4518d7059638df2821b8a0947f74eaf2cRaph Levien        for (int i = 0; i < sFallbackFonts.length; i++) {
245363e21b4518d7059638df2821b8a0947f74eaf2cRaph Levien            ptrArray[i + families.length] = sFallbackFonts[i].mNativePtr;
246363e21b4518d7059638df2821b8a0947f74eaf2cRaph Levien        }
247363e21b4518d7059638df2821b8a0947f74eaf2cRaph Levien        return new Typeface(nativeCreateFromArray(ptrArray));
248363e21b4518d7059638df2821b8a0947f74eaf2cRaph Levien    }
249363e21b4518d7059638df2821b8a0947f74eaf2cRaph Levien
2509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // don't allow clients to call this directly
25136bef0bf30d6bae48cf3837df351075ca4fce654Ashok Bhat    private Typeface(long ni) {
25246926698996d3857a650ed535024a88dbeaff1e1Romain Guy        if (ni == 0) {
25331a69fdbe1edd8d686043e8ca7d278289f65808eMike Reed            throw new RuntimeException("native typeface cannot be made");
25431a69fdbe1edd8d686043e8ca7d278289f65808eMike Reed        }
25546926698996d3857a650ed535024a88dbeaff1e1Romain Guy
2569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        native_instance = ni;
25746926698996d3857a650ed535024a88dbeaff1e1Romain Guy        mStyle = nativeGetStyle(ni);
2589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2599a5b61ccc83303ceeec2059f58c1977af9faa9e3Raph Levien
2609a5b61ccc83303ceeec2059f58c1977af9faa9e3Raph Levien    private static FontFamily makeFamilyFromParsed(FontListParser.Family family) {
2619a5b61ccc83303ceeec2059f58c1977af9faa9e3Raph Levien        // TODO: expand to handle attributes like lang and variant
262f9e3d311275c37fe5f2562993687a1627780a6d0Raph Levien        FontFamily fontFamily = new FontFamily(family.lang, family.variant);
2639a5b61ccc83303ceeec2059f58c1977af9faa9e3Raph Levien        for (String fontFile : family.fontFiles) {
264d573794d83a049fe59e289944f0cd77406dd776aRaph Levien            fontFamily.addFont(fontFile);
2659a5b61ccc83303ceeec2059f58c1977af9faa9e3Raph Levien        }
2669a5b61ccc83303ceeec2059f58c1977af9faa9e3Raph Levien        return fontFamily;
2679a5b61ccc83303ceeec2059f58c1977af9faa9e3Raph Levien    }
2689a5b61ccc83303ceeec2059f58c1977af9faa9e3Raph Levien
269baef8c1ffe5c900fb0da9512654bf249b5fc9269Deepanshu Gupta    /*
270baef8c1ffe5c900fb0da9512654bf249b5fc9269Deepanshu Gupta     * (non-Javadoc)
271baef8c1ffe5c900fb0da9512654bf249b5fc9269Deepanshu Gupta     *
272baef8c1ffe5c900fb0da9512654bf249b5fc9269Deepanshu Gupta     * This should only be called once, from the static class initializer block.
273baef8c1ffe5c900fb0da9512654bf249b5fc9269Deepanshu Gupta     */
274baef8c1ffe5c900fb0da9512654bf249b5fc9269Deepanshu Gupta    private static void init() {
2759a5b61ccc83303ceeec2059f58c1977af9faa9e3Raph Levien        // Load font config and initialize Minikin state
276baef8c1ffe5c900fb0da9512654bf249b5fc9269Deepanshu Gupta        File systemFontConfigLocation = getSystemFontConfigLocation();
277baef8c1ffe5c900fb0da9512654bf249b5fc9269Deepanshu Gupta        File systemConfigFilename = new File(systemFontConfigLocation, SYSTEM_FONTS_CONFIG);
278baef8c1ffe5c900fb0da9512654bf249b5fc9269Deepanshu Gupta        File configFilename = new File(systemFontConfigLocation, FALLBACK_FONTS_CONFIG);
2799a5b61ccc83303ceeec2059f58c1977af9faa9e3Raph Levien        try {
2809a5b61ccc83303ceeec2059f58c1977af9faa9e3Raph Levien            // TODO: throws an exception non-Minikin builds, to fail early;
2819a5b61ccc83303ceeec2059f58c1977af9faa9e3Raph Levien            // remove when Minikin-only
2829a5b61ccc83303ceeec2059f58c1977af9faa9e3Raph Levien            new FontFamily();
2839a5b61ccc83303ceeec2059f58c1977af9faa9e3Raph Levien
2849a5b61ccc83303ceeec2059f58c1977af9faa9e3Raph Levien            FileInputStream systemIn = new FileInputStream(systemConfigFilename);
2859a5b61ccc83303ceeec2059f58c1977af9faa9e3Raph Levien            List<FontListParser.Family> systemFontConfig = FontListParser.parse(systemIn);
286363e21b4518d7059638df2821b8a0947f74eaf2cRaph Levien
287363e21b4518d7059638df2821b8a0947f74eaf2cRaph Levien            FileInputStream fallbackIn = new FileInputStream(configFilename);
288363e21b4518d7059638df2821b8a0947f74eaf2cRaph Levien            List<FontFamily> familyList = new ArrayList<FontFamily>();
289363e21b4518d7059638df2821b8a0947f74eaf2cRaph Levien            // Note that the default typeface is always present in the fallback list;
290363e21b4518d7059638df2821b8a0947f74eaf2cRaph Levien            // this is an enhancement from pre-Minikin behavior.
291363e21b4518d7059638df2821b8a0947f74eaf2cRaph Levien            familyList.add(makeFamilyFromParsed(systemFontConfig.get(0)));
292363e21b4518d7059638df2821b8a0947f74eaf2cRaph Levien            for (Family f : FontListParser.parse(fallbackIn)) {
293363e21b4518d7059638df2821b8a0947f74eaf2cRaph Levien                familyList.add(makeFamilyFromParsed(f));
294363e21b4518d7059638df2821b8a0947f74eaf2cRaph Levien            }
295363e21b4518d7059638df2821b8a0947f74eaf2cRaph Levien            sFallbackFonts = familyList.toArray(new FontFamily[familyList.size()]);
296363e21b4518d7059638df2821b8a0947f74eaf2cRaph Levien            setDefault(Typeface.createFromFamilies(sFallbackFonts));
297363e21b4518d7059638df2821b8a0947f74eaf2cRaph Levien
2989a5b61ccc83303ceeec2059f58c1977af9faa9e3Raph Levien            Map<String, Typeface> systemFonts = new HashMap<String, Typeface>();
299363e21b4518d7059638df2821b8a0947f74eaf2cRaph Levien            for (int i = 0; i < systemFontConfig.size(); i++) {
300363e21b4518d7059638df2821b8a0947f74eaf2cRaph Levien                Typeface typeface;
301363e21b4518d7059638df2821b8a0947f74eaf2cRaph Levien                Family f = systemFontConfig.get(i);
302363e21b4518d7059638df2821b8a0947f74eaf2cRaph Levien                if (i == 0) {
303363e21b4518d7059638df2821b8a0947f74eaf2cRaph Levien                    // The first entry is the default typeface; no sense in duplicating
304363e21b4518d7059638df2821b8a0947f74eaf2cRaph Levien                    // the corresponding FontFamily.
305363e21b4518d7059638df2821b8a0947f74eaf2cRaph Levien                    typeface = sDefaultTypeface;
306363e21b4518d7059638df2821b8a0947f74eaf2cRaph Levien                } else {
307363e21b4518d7059638df2821b8a0947f74eaf2cRaph Levien                    FontFamily fontFamily = makeFamilyFromParsed(f);
308363e21b4518d7059638df2821b8a0947f74eaf2cRaph Levien                    FontFamily[] families = { fontFamily };
309363e21b4518d7059638df2821b8a0947f74eaf2cRaph Levien                    typeface = Typeface.createFromFamiliesWithDefault(families);
310363e21b4518d7059638df2821b8a0947f74eaf2cRaph Levien                }
3119a5b61ccc83303ceeec2059f58c1977af9faa9e3Raph Levien                for (String name : f.names) {
3129a5b61ccc83303ceeec2059f58c1977af9faa9e3Raph Levien                    systemFonts.put(name, typeface);
3139a5b61ccc83303ceeec2059f58c1977af9faa9e3Raph Levien                }
3149a5b61ccc83303ceeec2059f58c1977af9faa9e3Raph Levien            }
3159a5b61ccc83303ceeec2059f58c1977af9faa9e3Raph Levien            sSystemFontMap = systemFonts;
3169a5b61ccc83303ceeec2059f58c1977af9faa9e3Raph Levien
3179a5b61ccc83303ceeec2059f58c1977af9faa9e3Raph Levien        } catch (RuntimeException e) {
3189a5b61ccc83303ceeec2059f58c1977af9faa9e3Raph Levien            Log.w(TAG, "Didn't create default family (most likely, non-Minikin build)");
3199a5b61ccc83303ceeec2059f58c1977af9faa9e3Raph Levien            // TODO: normal in non-Minikin case, remove or make error when Minikin-only
3209a5b61ccc83303ceeec2059f58c1977af9faa9e3Raph Levien        } catch (FileNotFoundException e) {
3219a5b61ccc83303ceeec2059f58c1977af9faa9e3Raph Levien            Log.e(TAG, "Error opening " + configFilename);
3229a5b61ccc83303ceeec2059f58c1977af9faa9e3Raph Levien        } catch (IOException e) {
3239a5b61ccc83303ceeec2059f58c1977af9faa9e3Raph Levien            Log.e(TAG, "Error reading " + configFilename);
3249a5b61ccc83303ceeec2059f58c1977af9faa9e3Raph Levien        } catch (XmlPullParserException e) {
3259a5b61ccc83303ceeec2059f58c1977af9faa9e3Raph Levien            Log.e(TAG, "XML parse exception for " + configFilename);
3269a5b61ccc83303ceeec2059f58c1977af9faa9e3Raph Levien        }
327baef8c1ffe5c900fb0da9512654bf249b5fc9269Deepanshu Gupta    }
3289a5b61ccc83303ceeec2059f58c1977af9faa9e3Raph Levien
329baef8c1ffe5c900fb0da9512654bf249b5fc9269Deepanshu Gupta    static {
330baef8c1ffe5c900fb0da9512654bf249b5fc9269Deepanshu Gupta        init();
3319a5b61ccc83303ceeec2059f58c1977af9faa9e3Raph Levien        // Set up defaults and typefaces exposed in public API
33246926698996d3857a650ed535024a88dbeaff1e1Romain Guy        DEFAULT         = create((String) null, 0);
33346926698996d3857a650ed535024a88dbeaff1e1Romain Guy        DEFAULT_BOLD    = create((String) null, Typeface.BOLD);
3349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        SANS_SERIF      = create("sans-serif", 0);
3359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        SERIF           = create("serif", 0);
3369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        MONOSPACE       = create("monospace", 0);
3379a5b61ccc83303ceeec2059f58c1977af9faa9e3Raph Levien
3389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        sDefaults = new Typeface[] {
3399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            DEFAULT,
3409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            DEFAULT_BOLD,
34146926698996d3857a650ed535024a88dbeaff1e1Romain Guy            create((String) null, Typeface.ITALIC),
34246926698996d3857a650ed535024a88dbeaff1e1Romain Guy            create((String) null, Typeface.BOLD_ITALIC),
3439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        };
344baef8c1ffe5c900fb0da9512654bf249b5fc9269Deepanshu Gupta
345baef8c1ffe5c900fb0da9512654bf249b5fc9269Deepanshu Gupta    }
346baef8c1ffe5c900fb0da9512654bf249b5fc9269Deepanshu Gupta
347baef8c1ffe5c900fb0da9512654bf249b5fc9269Deepanshu Gupta    private static File getSystemFontConfigLocation() {
348baef8c1ffe5c900fb0da9512654bf249b5fc9269Deepanshu Gupta        return new File("/system/etc/");
3499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3519a5b61ccc83303ceeec2059f58c1977af9faa9e3Raph Levien    @Override
3529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    protected void finalize() throws Throwable {
35346926698996d3857a650ed535024a88dbeaff1e1Romain Guy        try {
35446926698996d3857a650ed535024a88dbeaff1e1Romain Guy            nativeUnref(native_instance);
35546926698996d3857a650ed535024a88dbeaff1e1Romain Guy        } finally {
35646926698996d3857a650ed535024a88dbeaff1e1Romain Guy            super.finalize();
35746926698996d3857a650ed535024a88dbeaff1e1Romain Guy        }
35846926698996d3857a650ed535024a88dbeaff1e1Romain Guy    }
35946926698996d3857a650ed535024a88dbeaff1e1Romain Guy
36046926698996d3857a650ed535024a88dbeaff1e1Romain Guy    @Override
36146926698996d3857a650ed535024a88dbeaff1e1Romain Guy    public boolean equals(Object o) {
36246926698996d3857a650ed535024a88dbeaff1e1Romain Guy        if (this == o) return true;
36346926698996d3857a650ed535024a88dbeaff1e1Romain Guy        if (o == null || getClass() != o.getClass()) return false;
36446926698996d3857a650ed535024a88dbeaff1e1Romain Guy
36546926698996d3857a650ed535024a88dbeaff1e1Romain Guy        Typeface typeface = (Typeface) o;
36646926698996d3857a650ed535024a88dbeaff1e1Romain Guy
36746926698996d3857a650ed535024a88dbeaff1e1Romain Guy        return mStyle == typeface.mStyle && native_instance == typeface.native_instance;
36846926698996d3857a650ed535024a88dbeaff1e1Romain Guy    }
36946926698996d3857a650ed535024a88dbeaff1e1Romain Guy
37046926698996d3857a650ed535024a88dbeaff1e1Romain Guy    @Override
37146926698996d3857a650ed535024a88dbeaff1e1Romain Guy    public int hashCode() {
37236bef0bf30d6bae48cf3837df351075ca4fce654Ashok Bhat        /*
37336bef0bf30d6bae48cf3837df351075ca4fce654Ashok Bhat         * Modified method for hashCode with long native_instance derived from
37436bef0bf30d6bae48cf3837df351075ca4fce654Ashok Bhat         * http://developer.android.com/reference/java/lang/Object.html
37536bef0bf30d6bae48cf3837df351075ca4fce654Ashok Bhat         */
37636bef0bf30d6bae48cf3837df351075ca4fce654Ashok Bhat        int result = 17;
37736bef0bf30d6bae48cf3837df351075ca4fce654Ashok Bhat        result = 31 * result + (int) (native_instance ^ (native_instance >>> 32));
37846926698996d3857a650ed535024a88dbeaff1e1Romain Guy        result = 31 * result + mStyle;
37946926698996d3857a650ed535024a88dbeaff1e1Romain Guy        return result;
3809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
38236bef0bf30d6bae48cf3837df351075ca4fce654Ashok Bhat    private static native long nativeCreateFromTypeface(long native_instance, int style);
38336bef0bf30d6bae48cf3837df351075ca4fce654Ashok Bhat    private static native void nativeUnref(long native_instance);
38436bef0bf30d6bae48cf3837df351075ca4fce654Ashok Bhat    private static native int  nativeGetStyle(long native_instance);
3851a73f732f91e97c9c66b808c245ddda36a10e987Raph Levien    private static native long nativeCreateFromArray(long[] familyArray);
3869a5b61ccc83303ceeec2059f58c1977af9faa9e3Raph Levien    private static native void nativeSetDefault(long native_instance);
3879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
388