Typeface.java revision a87b07d7fafd59ae26073a80cd742b17ea427ecd
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;
201a73f732f91e97c9c66b808c245ddda36a10e987Raph Levienimport android.util.Log;
2136bef0bf30d6bae48cf3837df351075ca4fce654Ashok Bhatimport android.util.LongSparseArray;
229a5b61ccc83303ceeec2059f58c1977af9faa9e3Raph Levienimport android.util.SparseArray;
239a5b61ccc83303ceeec2059f58c1977af9faa9e3Raph Levien
249a5b61ccc83303ceeec2059f58c1977af9faa9e3Raph Levienimport org.xmlpull.v1.XmlPullParserException;
259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
26a87a132ebf1c2dd733cf52feff6e44525257c961Romain Guyimport java.io.File;
279a5b61ccc83303ceeec2059f58c1977af9faa9e3Raph Levienimport java.io.FileInputStream;
289a5b61ccc83303ceeec2059f58c1977af9faa9e3Raph Levienimport java.io.FileNotFoundException;
299a5b61ccc83303ceeec2059f58c1977af9faa9e3Raph Levienimport java.io.IOException;
309a5b61ccc83303ceeec2059f58c1977af9faa9e3Raph Levienimport java.util.ArrayList;
319a5b61ccc83303ceeec2059f58c1977af9faa9e3Raph Levienimport java.util.HashMap;
329a5b61ccc83303ceeec2059f58c1977af9faa9e3Raph Levienimport java.util.List;
339a5b61ccc83303ceeec2059f58c1977af9faa9e3Raph Levienimport java.util.Map;
34a87a132ebf1c2dd733cf52feff6e44525257c961Romain Guy
359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/**
369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * The Typeface class specifies the typeface and intrinsic style of a font.
379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * This is used in the paint, along with optionally Paint settings like
389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * textSize, textSkewX, textScaleX to specify
399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * how text appears when drawn (and measured).
409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpublic class Typeface {
429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
439a5b61ccc83303ceeec2059f58c1977af9faa9e3Raph Levien    private static String TAG = "Typeface";
449a5b61ccc83303ceeec2059f58c1977af9faa9e3Raph Levien
459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** The default NORMAL typeface object */
469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static final Typeface DEFAULT;
479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * The default BOLD typeface object. Note: this may be not actually be
499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * bold, depending on what fonts are installed. Call getStyle() to know
509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * for sure.
519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static final Typeface DEFAULT_BOLD;
539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** The NORMAL style of the default sans serif typeface. */
549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static final Typeface SANS_SERIF;
559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** The NORMAL style of the default serif typeface. */
569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static final Typeface SERIF;
579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** The NORMAL style of the default monospace typeface. */
589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static final Typeface MONOSPACE;
599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6046926698996d3857a650ed535024a88dbeaff1e1Romain Guy    static Typeface[] sDefaults;
6136bef0bf30d6bae48cf3837df351075ca4fce654Ashok Bhat    private static final LongSparseArray<SparseArray<Typeface>> sTypefaceCache =
6236bef0bf30d6bae48cf3837df351075ca4fce654Ashok Bhat            new LongSparseArray<SparseArray<Typeface>>(3);
6346926698996d3857a650ed535024a88dbeaff1e1Romain Guy
649a5b61ccc83303ceeec2059f58c1977af9faa9e3Raph Levien    static Typeface sDefaultTypeface;
659a5b61ccc83303ceeec2059f58c1977af9faa9e3Raph Levien    static Map<String, Typeface> sSystemFontMap;
66363e21b4518d7059638df2821b8a0947f74eaf2cRaph Levien    static FontFamily[] sFallbackFonts;
679a5b61ccc83303ceeec2059f58c1977af9faa9e3Raph Levien
68117cbebe810613d4a6de034f02652cdbbfef4cdeRaph Levien    static final String FONTS_CONFIG = "fonts.xml";
69baef8c1ffe5c900fb0da9512654bf249b5fc9269Deepanshu Gupta
70a033630e805c407080221e20b236b6054f324670Raph Levien    /**
71a033630e805c407080221e20b236b6054f324670Raph Levien     * @hide
72a033630e805c407080221e20b236b6054f324670Raph Levien     */
7336bef0bf30d6bae48cf3837df351075ca4fce654Ashok Bhat    public long native_instance;
749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // Style
769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static final int NORMAL = 0;
779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static final int BOLD = 1;
789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static final int ITALIC = 2;
799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static final int BOLD_ITALIC = 3;
809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8146926698996d3857a650ed535024a88dbeaff1e1Romain Guy    private int mStyle = 0;
8246926698996d3857a650ed535024a88dbeaff1e1Romain Guy
839a5b61ccc83303ceeec2059f58c1977af9faa9e3Raph Levien    private static void setDefault(Typeface t) {
849a5b61ccc83303ceeec2059f58c1977af9faa9e3Raph Levien        sDefaultTypeface = t;
859a5b61ccc83303ceeec2059f58c1977af9faa9e3Raph Levien        nativeSetDefault(t.native_instance);
869a5b61ccc83303ceeec2059f58c1977af9faa9e3Raph Levien    }
879a5b61ccc83303ceeec2059f58c1977af9faa9e3Raph Levien
889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** Returns the typeface's intrinsic style attributes */
899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public int getStyle() {
9046926698996d3857a650ed535024a88dbeaff1e1Romain Guy        return mStyle;
919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** Returns true if getStyle() has the BOLD bit set. */
949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public final boolean isBold() {
9546926698996d3857a650ed535024a88dbeaff1e1Romain Guy        return (mStyle & BOLD) != 0;
969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** Returns true if getStyle() has the ITALIC bit set. */
999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public final boolean isItalic() {
10046926698996d3857a650ed535024a88dbeaff1e1Romain Guy        return (mStyle & ITALIC) != 0;
1019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
1049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Create a typeface object given a family name, and option style information.
1059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * If null is passed for the name, then the "default" font will be chosen.
1069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * The resulting typeface object can be queried (getStyle()) to discover what
1079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * its "real" style characteristics are.
1089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
1099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param familyName May be null. The name of the font family.
1109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param style  The style (normal, bold, italic) of the typeface.
1119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *               e.g. NORMAL, BOLD, ITALIC, BOLD_ITALIC
1129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return The best matching typeface.
1139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
1149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static Typeface create(String familyName, int style) {
1159a5b61ccc83303ceeec2059f58c1977af9faa9e3Raph Levien        if (sSystemFontMap != null) {
1169a5b61ccc83303ceeec2059f58c1977af9faa9e3Raph Levien            return create(sSystemFontMap.get(familyName), style);
1179a5b61ccc83303ceeec2059f58c1977af9faa9e3Raph Levien        }
1183660789f06c5fbcb81e6c7c79612048bff8f0f66Raph Levien        return null;
1199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
1229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Create a typeface object that best matches the specified existing
1239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * typeface and the specified Style. Use this call if you want to pick a new
1249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * style from the same family of an existing typeface object. If family is
1259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * null, this selects from the default font's family.
1269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
1279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param family May be null. The name of the existing type face.
1289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param style  The style (normal, bold, italic) of the typeface.
1299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *               e.g. NORMAL, BOLD, ITALIC, BOLD_ITALIC
1309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return The best matching typeface.
1319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
1329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static Typeface create(Typeface family, int style) {
133ff86bcd08827d1050a8cfd99b521c21848b3f364Raph Levien        if (style < 0 || style > 3) {
134ff86bcd08827d1050a8cfd99b521c21848b3f364Raph Levien            style = 0;
135ff86bcd08827d1050a8cfd99b521c21848b3f364Raph Levien        }
13636bef0bf30d6bae48cf3837df351075ca4fce654Ashok Bhat        long ni = 0;
1379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (family != null) {
13846926698996d3857a650ed535024a88dbeaff1e1Romain Guy            // Return early if we're asked for the same face/style
13946926698996d3857a650ed535024a88dbeaff1e1Romain Guy            if (family.mStyle == style) {
14046926698996d3857a650ed535024a88dbeaff1e1Romain Guy                return family;
14146926698996d3857a650ed535024a88dbeaff1e1Romain Guy            }
14246926698996d3857a650ed535024a88dbeaff1e1Romain Guy
1439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            ni = family.native_instance;
1449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
14546926698996d3857a650ed535024a88dbeaff1e1Romain Guy
14646926698996d3857a650ed535024a88dbeaff1e1Romain Guy        Typeface typeface;
14746926698996d3857a650ed535024a88dbeaff1e1Romain Guy        SparseArray<Typeface> styles = sTypefaceCache.get(ni);
14846926698996d3857a650ed535024a88dbeaff1e1Romain Guy
14946926698996d3857a650ed535024a88dbeaff1e1Romain Guy        if (styles != null) {
15046926698996d3857a650ed535024a88dbeaff1e1Romain Guy            typeface = styles.get(style);
15146926698996d3857a650ed535024a88dbeaff1e1Romain Guy            if (typeface != null) {
15246926698996d3857a650ed535024a88dbeaff1e1Romain Guy                return typeface;
15346926698996d3857a650ed535024a88dbeaff1e1Romain Guy            }
15446926698996d3857a650ed535024a88dbeaff1e1Romain Guy        }
15546926698996d3857a650ed535024a88dbeaff1e1Romain Guy
15646926698996d3857a650ed535024a88dbeaff1e1Romain Guy        typeface = new Typeface(nativeCreateFromTypeface(ni, style));
15746926698996d3857a650ed535024a88dbeaff1e1Romain Guy        if (styles == null) {
15846926698996d3857a650ed535024a88dbeaff1e1Romain Guy            styles = new SparseArray<Typeface>(4);
15946926698996d3857a650ed535024a88dbeaff1e1Romain Guy            sTypefaceCache.put(ni, styles);
16046926698996d3857a650ed535024a88dbeaff1e1Romain Guy        }
16146926698996d3857a650ed535024a88dbeaff1e1Romain Guy        styles.put(style, typeface);
16246926698996d3857a650ed535024a88dbeaff1e1Romain Guy
16346926698996d3857a650ed535024a88dbeaff1e1Romain Guy        return typeface;
1649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
1679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Returns one of the default typeface objects, based on the specified style
1689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
1699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return the default typeface that corresponds to the style
1709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
1719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static Typeface defaultFromStyle(int style) {
1729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return sDefaults[style];
1739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1749a5b61ccc83303ceeec2059f58c1977af9faa9e3Raph Levien
1759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
1769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Create a new typeface from the specified font data.
1779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param mgr The application's asset manager
1789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param path  The file name of the font data in the assets directory
1799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return The new typeface.
1809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
1819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static Typeface createFromAsset(AssetManager mgr, String path) {
182d573794d83a049fe59e289944f0cd77406dd776aRaph Levien        if (sFallbackFonts != null) {
183d573794d83a049fe59e289944f0cd77406dd776aRaph Levien            FontFamily fontFamily = new FontFamily();
184d573794d83a049fe59e289944f0cd77406dd776aRaph Levien            if (fontFamily.addFontFromAsset(mgr, path)) {
185d573794d83a049fe59e289944f0cd77406dd776aRaph Levien                FontFamily[] families = { fontFamily };
186d573794d83a049fe59e289944f0cd77406dd776aRaph Levien                return createFromFamiliesWithDefault(families);
187d573794d83a049fe59e289944f0cd77406dd776aRaph Levien            }
188d573794d83a049fe59e289944f0cd77406dd776aRaph Levien        }
189bf8d5620f7f3be72ec217f4bcc14a417d4e1dee6Behdad Esfahbod        throw new RuntimeException("Font asset not found " + path);
1909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
191a87a132ebf1c2dd733cf52feff6e44525257c961Romain Guy
192a87a132ebf1c2dd733cf52feff6e44525257c961Romain Guy    /**
193a87a132ebf1c2dd733cf52feff6e44525257c961Romain Guy     * Create a new typeface from the specified font file.
194a87a132ebf1c2dd733cf52feff6e44525257c961Romain Guy     *
1959a5b61ccc83303ceeec2059f58c1977af9faa9e3Raph Levien     * @param path The path to the font data.
196a87a132ebf1c2dd733cf52feff6e44525257c961Romain Guy     * @return The new typeface.
197a87a132ebf1c2dd733cf52feff6e44525257c961Romain Guy     */
198a87a132ebf1c2dd733cf52feff6e44525257c961Romain Guy    public static Typeface createFromFile(File path) {
199d573794d83a049fe59e289944f0cd77406dd776aRaph Levien        return createFromFile(path.getAbsolutePath());
200a87a132ebf1c2dd733cf52feff6e44525257c961Romain Guy    }
201a87a132ebf1c2dd733cf52feff6e44525257c961Romain Guy
202a87a132ebf1c2dd733cf52feff6e44525257c961Romain Guy    /**
203a87a132ebf1c2dd733cf52feff6e44525257c961Romain Guy     * Create a new typeface from the specified font file.
204a87a132ebf1c2dd733cf52feff6e44525257c961Romain Guy     *
2059a5b61ccc83303ceeec2059f58c1977af9faa9e3Raph Levien     * @param path The full path to the font data.
206a87a132ebf1c2dd733cf52feff6e44525257c961Romain Guy     * @return The new typeface.
207a87a132ebf1c2dd733cf52feff6e44525257c961Romain Guy     */
208a87a132ebf1c2dd733cf52feff6e44525257c961Romain Guy    public static Typeface createFromFile(String path) {
209d573794d83a049fe59e289944f0cd77406dd776aRaph Levien        if (sFallbackFonts != null) {
210d573794d83a049fe59e289944f0cd77406dd776aRaph Levien            FontFamily fontFamily = new FontFamily();
2113fa667e22401bf3ba96957fe31167bf05d164c55Seigo Nonaka            if (fontFamily.addFont(path, 0 /* ttcIndex */)) {
212d573794d83a049fe59e289944f0cd77406dd776aRaph Levien                FontFamily[] families = { fontFamily };
213d573794d83a049fe59e289944f0cd77406dd776aRaph Levien                return createFromFamiliesWithDefault(families);
214d573794d83a049fe59e289944f0cd77406dd776aRaph Levien            }
215d573794d83a049fe59e289944f0cd77406dd776aRaph Levien        }
216bf8d5620f7f3be72ec217f4bcc14a417d4e1dee6Behdad Esfahbod        throw new RuntimeException("Font not found " + path);
217a87a132ebf1c2dd733cf52feff6e44525257c961Romain Guy    }
218a87a132ebf1c2dd733cf52feff6e44525257c961Romain Guy
2191a73f732f91e97c9c66b808c245ddda36a10e987Raph Levien    /**
2201a73f732f91e97c9c66b808c245ddda36a10e987Raph Levien     * Create a new typeface from an array of font families.
2211a73f732f91e97c9c66b808c245ddda36a10e987Raph Levien     *
2221a73f732f91e97c9c66b808c245ddda36a10e987Raph Levien     * @param families array of font families
2231a73f732f91e97c9c66b808c245ddda36a10e987Raph Levien     * @hide
2241a73f732f91e97c9c66b808c245ddda36a10e987Raph Levien     */
2251a73f732f91e97c9c66b808c245ddda36a10e987Raph Levien    public static Typeface createFromFamilies(FontFamily[] families) {
2261a73f732f91e97c9c66b808c245ddda36a10e987Raph Levien        long[] ptrArray = new long[families.length];
2271a73f732f91e97c9c66b808c245ddda36a10e987Raph Levien        for (int i = 0; i < families.length; i++) {
2281a73f732f91e97c9c66b808c245ddda36a10e987Raph Levien            ptrArray[i] = families[i].mNativePtr;
2291a73f732f91e97c9c66b808c245ddda36a10e987Raph Levien        }
2301a73f732f91e97c9c66b808c245ddda36a10e987Raph Levien        return new Typeface(nativeCreateFromArray(ptrArray));
2311a73f732f91e97c9c66b808c245ddda36a10e987Raph Levien    }
2321a73f732f91e97c9c66b808c245ddda36a10e987Raph Levien
233363e21b4518d7059638df2821b8a0947f74eaf2cRaph Levien    /**
234363e21b4518d7059638df2821b8a0947f74eaf2cRaph Levien     * Create a new typeface from an array of font families, including
235363e21b4518d7059638df2821b8a0947f74eaf2cRaph Levien     * also the font families in the fallback list.
236363e21b4518d7059638df2821b8a0947f74eaf2cRaph Levien     *
237363e21b4518d7059638df2821b8a0947f74eaf2cRaph Levien     * @param families array of font families
238363e21b4518d7059638df2821b8a0947f74eaf2cRaph Levien     * @hide
239363e21b4518d7059638df2821b8a0947f74eaf2cRaph Levien     */
240363e21b4518d7059638df2821b8a0947f74eaf2cRaph Levien    public static Typeface createFromFamiliesWithDefault(FontFamily[] families) {
241363e21b4518d7059638df2821b8a0947f74eaf2cRaph Levien        long[] ptrArray = new long[families.length + sFallbackFonts.length];
242363e21b4518d7059638df2821b8a0947f74eaf2cRaph Levien        for (int i = 0; i < families.length; i++) {
243363e21b4518d7059638df2821b8a0947f74eaf2cRaph Levien            ptrArray[i] = families[i].mNativePtr;
244363e21b4518d7059638df2821b8a0947f74eaf2cRaph Levien        }
245363e21b4518d7059638df2821b8a0947f74eaf2cRaph Levien        for (int i = 0; i < sFallbackFonts.length; i++) {
246363e21b4518d7059638df2821b8a0947f74eaf2cRaph Levien            ptrArray[i + families.length] = sFallbackFonts[i].mNativePtr;
247363e21b4518d7059638df2821b8a0947f74eaf2cRaph Levien        }
248363e21b4518d7059638df2821b8a0947f74eaf2cRaph Levien        return new Typeface(nativeCreateFromArray(ptrArray));
249363e21b4518d7059638df2821b8a0947f74eaf2cRaph Levien    }
250363e21b4518d7059638df2821b8a0947f74eaf2cRaph Levien
2519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // don't allow clients to call this directly
25236bef0bf30d6bae48cf3837df351075ca4fce654Ashok Bhat    private Typeface(long ni) {
25346926698996d3857a650ed535024a88dbeaff1e1Romain Guy        if (ni == 0) {
25431a69fdbe1edd8d686043e8ca7d278289f65808eMike Reed            throw new RuntimeException("native typeface cannot be made");
25531a69fdbe1edd8d686043e8ca7d278289f65808eMike Reed        }
25646926698996d3857a650ed535024a88dbeaff1e1Romain Guy
2579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        native_instance = ni;
25846926698996d3857a650ed535024a88dbeaff1e1Romain Guy        mStyle = nativeGetStyle(ni);
2599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2609a5b61ccc83303ceeec2059f58c1977af9faa9e3Raph Levien
2619a5b61ccc83303ceeec2059f58c1977af9faa9e3Raph Levien    private static FontFamily makeFamilyFromParsed(FontListParser.Family family) {
262f9e3d311275c37fe5f2562993687a1627780a6d0Raph Levien        FontFamily fontFamily = new FontFamily(family.lang, family.variant);
263117cbebe810613d4a6de034f02652cdbbfef4cdeRaph Levien        for (FontListParser.Font font : family.fonts) {
264a87b07d7fafd59ae26073a80cd742b17ea427ecdBen Wagner            fontFamily.addFontWeightStyle(font.fontName, font.ttcIndex, font.axes,
265a87b07d7fafd59ae26073a80cd742b17ea427ecdBen Wagner                    font.weight, font.isItalic);
2669a5b61ccc83303ceeec2059f58c1977af9faa9e3Raph Levien        }
2679a5b61ccc83303ceeec2059f58c1977af9faa9e3Raph Levien        return fontFamily;
2689a5b61ccc83303ceeec2059f58c1977af9faa9e3Raph Levien    }
2699a5b61ccc83303ceeec2059f58c1977af9faa9e3Raph Levien
270baef8c1ffe5c900fb0da9512654bf249b5fc9269Deepanshu Gupta    /*
271baef8c1ffe5c900fb0da9512654bf249b5fc9269Deepanshu Gupta     * (non-Javadoc)
272baef8c1ffe5c900fb0da9512654bf249b5fc9269Deepanshu Gupta     *
273baef8c1ffe5c900fb0da9512654bf249b5fc9269Deepanshu Gupta     * This should only be called once, from the static class initializer block.
274baef8c1ffe5c900fb0da9512654bf249b5fc9269Deepanshu Gupta     */
275baef8c1ffe5c900fb0da9512654bf249b5fc9269Deepanshu Gupta    private static void init() {
2769a5b61ccc83303ceeec2059f58c1977af9faa9e3Raph Levien        // Load font config and initialize Minikin state
277baef8c1ffe5c900fb0da9512654bf249b5fc9269Deepanshu Gupta        File systemFontConfigLocation = getSystemFontConfigLocation();
278117cbebe810613d4a6de034f02652cdbbfef4cdeRaph Levien        File configFilename = new File(systemFontConfigLocation, FONTS_CONFIG);
2799a5b61ccc83303ceeec2059f58c1977af9faa9e3Raph Levien        try {
280117cbebe810613d4a6de034f02652cdbbfef4cdeRaph Levien            FileInputStream fontsIn = new FileInputStream(configFilename);
281117cbebe810613d4a6de034f02652cdbbfef4cdeRaph Levien            FontListParser.Config fontConfig = FontListParser.parse(fontsIn);
2829a5b61ccc83303ceeec2059f58c1977af9faa9e3Raph Levien
283363e21b4518d7059638df2821b8a0947f74eaf2cRaph Levien            List<FontFamily> familyList = new ArrayList<FontFamily>();
284363e21b4518d7059638df2821b8a0947f74eaf2cRaph Levien            // Note that the default typeface is always present in the fallback list;
285363e21b4518d7059638df2821b8a0947f74eaf2cRaph Levien            // this is an enhancement from pre-Minikin behavior.
286117cbebe810613d4a6de034f02652cdbbfef4cdeRaph Levien            for (int i = 0; i < fontConfig.families.size(); i++) {
287a87b07d7fafd59ae26073a80cd742b17ea427ecdBen Wagner                FontListParser.Family f = fontConfig.families.get(i);
288117cbebe810613d4a6de034f02652cdbbfef4cdeRaph Levien                if (i == 0 || f.name == null) {
289117cbebe810613d4a6de034f02652cdbbfef4cdeRaph Levien                    familyList.add(makeFamilyFromParsed(f));
290117cbebe810613d4a6de034f02652cdbbfef4cdeRaph Levien                }
291363e21b4518d7059638df2821b8a0947f74eaf2cRaph Levien            }
292363e21b4518d7059638df2821b8a0947f74eaf2cRaph Levien            sFallbackFonts = familyList.toArray(new FontFamily[familyList.size()]);
293363e21b4518d7059638df2821b8a0947f74eaf2cRaph Levien            setDefault(Typeface.createFromFamilies(sFallbackFonts));
294363e21b4518d7059638df2821b8a0947f74eaf2cRaph Levien
2959a5b61ccc83303ceeec2059f58c1977af9faa9e3Raph Levien            Map<String, Typeface> systemFonts = new HashMap<String, Typeface>();
296117cbebe810613d4a6de034f02652cdbbfef4cdeRaph Levien            for (int i = 0; i < fontConfig.families.size(); i++) {
297363e21b4518d7059638df2821b8a0947f74eaf2cRaph Levien                Typeface typeface;
298a87b07d7fafd59ae26073a80cd742b17ea427ecdBen Wagner                FontListParser.Family f = fontConfig.families.get(i);
299117cbebe810613d4a6de034f02652cdbbfef4cdeRaph Levien                if (f.name != null) {
300117cbebe810613d4a6de034f02652cdbbfef4cdeRaph Levien                    if (i == 0) {
301117cbebe810613d4a6de034f02652cdbbfef4cdeRaph Levien                        // The first entry is the default typeface; no sense in
302117cbebe810613d4a6de034f02652cdbbfef4cdeRaph Levien                        // duplicating the corresponding FontFamily.
303117cbebe810613d4a6de034f02652cdbbfef4cdeRaph Levien                        typeface = sDefaultTypeface;
304117cbebe810613d4a6de034f02652cdbbfef4cdeRaph Levien                    } else {
305117cbebe810613d4a6de034f02652cdbbfef4cdeRaph Levien                        FontFamily fontFamily = makeFamilyFromParsed(f);
306117cbebe810613d4a6de034f02652cdbbfef4cdeRaph Levien                        FontFamily[] families = { fontFamily };
307117cbebe810613d4a6de034f02652cdbbfef4cdeRaph Levien                        typeface = Typeface.createFromFamiliesWithDefault(families);
308117cbebe810613d4a6de034f02652cdbbfef4cdeRaph Levien                    }
309117cbebe810613d4a6de034f02652cdbbfef4cdeRaph Levien                    systemFonts.put(f.name, typeface);
310363e21b4518d7059638df2821b8a0947f74eaf2cRaph Levien                }
311117cbebe810613d4a6de034f02652cdbbfef4cdeRaph Levien            }
312117cbebe810613d4a6de034f02652cdbbfef4cdeRaph Levien            for (FontListParser.Alias alias : fontConfig.aliases) {
313117cbebe810613d4a6de034f02652cdbbfef4cdeRaph Levien                Typeface base = systemFonts.get(alias.toName);
314117cbebe810613d4a6de034f02652cdbbfef4cdeRaph Levien                Typeface newFace = base;
315117cbebe810613d4a6de034f02652cdbbfef4cdeRaph Levien                int weight = alias.weight;
316117cbebe810613d4a6de034f02652cdbbfef4cdeRaph Levien                if (weight != 400) {
317117cbebe810613d4a6de034f02652cdbbfef4cdeRaph Levien                    newFace = new Typeface(nativeCreateWeightAlias(base.native_instance, weight));
3189a5b61ccc83303ceeec2059f58c1977af9faa9e3Raph Levien                }
319117cbebe810613d4a6de034f02652cdbbfef4cdeRaph Levien                systemFonts.put(alias.name, newFace);
3209a5b61ccc83303ceeec2059f58c1977af9faa9e3Raph Levien            }
3219a5b61ccc83303ceeec2059f58c1977af9faa9e3Raph Levien            sSystemFontMap = systemFonts;
3229a5b61ccc83303ceeec2059f58c1977af9faa9e3Raph Levien
3239a5b61ccc83303ceeec2059f58c1977af9faa9e3Raph Levien        } catch (RuntimeException e) {
324117cbebe810613d4a6de034f02652cdbbfef4cdeRaph Levien            Log.w(TAG, "Didn't create default family (most likely, non-Minikin build)", e);
3259a5b61ccc83303ceeec2059f58c1977af9faa9e3Raph Levien            // TODO: normal in non-Minikin case, remove or make error when Minikin-only
3269a5b61ccc83303ceeec2059f58c1977af9faa9e3Raph Levien        } catch (FileNotFoundException e) {
327a87b07d7fafd59ae26073a80cd742b17ea427ecdBen Wagner            Log.e(TAG, "Error opening " + configFilename, e);
3289a5b61ccc83303ceeec2059f58c1977af9faa9e3Raph Levien        } catch (IOException e) {
329a87b07d7fafd59ae26073a80cd742b17ea427ecdBen Wagner            Log.e(TAG, "Error reading " + configFilename, e);
3309a5b61ccc83303ceeec2059f58c1977af9faa9e3Raph Levien        } catch (XmlPullParserException e) {
331a87b07d7fafd59ae26073a80cd742b17ea427ecdBen Wagner            Log.e(TAG, "XML parse exception for " + configFilename, e);
3329a5b61ccc83303ceeec2059f58c1977af9faa9e3Raph Levien        }
333baef8c1ffe5c900fb0da9512654bf249b5fc9269Deepanshu Gupta    }
3349a5b61ccc83303ceeec2059f58c1977af9faa9e3Raph Levien
335baef8c1ffe5c900fb0da9512654bf249b5fc9269Deepanshu Gupta    static {
336baef8c1ffe5c900fb0da9512654bf249b5fc9269Deepanshu Gupta        init();
3379a5b61ccc83303ceeec2059f58c1977af9faa9e3Raph Levien        // Set up defaults and typefaces exposed in public API
33846926698996d3857a650ed535024a88dbeaff1e1Romain Guy        DEFAULT         = create((String) null, 0);
33946926698996d3857a650ed535024a88dbeaff1e1Romain Guy        DEFAULT_BOLD    = create((String) null, Typeface.BOLD);
3409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        SANS_SERIF      = create("sans-serif", 0);
3419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        SERIF           = create("serif", 0);
3429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        MONOSPACE       = create("monospace", 0);
3439a5b61ccc83303ceeec2059f58c1977af9faa9e3Raph Levien
3449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        sDefaults = new Typeface[] {
3459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            DEFAULT,
3469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            DEFAULT_BOLD,
34746926698996d3857a650ed535024a88dbeaff1e1Romain Guy            create((String) null, Typeface.ITALIC),
34846926698996d3857a650ed535024a88dbeaff1e1Romain Guy            create((String) null, Typeface.BOLD_ITALIC),
3499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        };
350baef8c1ffe5c900fb0da9512654bf249b5fc9269Deepanshu Gupta
351baef8c1ffe5c900fb0da9512654bf249b5fc9269Deepanshu Gupta    }
352baef8c1ffe5c900fb0da9512654bf249b5fc9269Deepanshu Gupta
353baef8c1ffe5c900fb0da9512654bf249b5fc9269Deepanshu Gupta    private static File getSystemFontConfigLocation() {
354baef8c1ffe5c900fb0da9512654bf249b5fc9269Deepanshu Gupta        return new File("/system/etc/");
3559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3579a5b61ccc83303ceeec2059f58c1977af9faa9e3Raph Levien    @Override
3589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    protected void finalize() throws Throwable {
35946926698996d3857a650ed535024a88dbeaff1e1Romain Guy        try {
36046926698996d3857a650ed535024a88dbeaff1e1Romain Guy            nativeUnref(native_instance);
361ffa84e008c712ceffa09d6b89a49882c88b3cca5Hans Boehm            native_instance = 0;  // Other finalizers can still call us.
36246926698996d3857a650ed535024a88dbeaff1e1Romain Guy        } finally {
36346926698996d3857a650ed535024a88dbeaff1e1Romain Guy            super.finalize();
36446926698996d3857a650ed535024a88dbeaff1e1Romain Guy        }
36546926698996d3857a650ed535024a88dbeaff1e1Romain Guy    }
36646926698996d3857a650ed535024a88dbeaff1e1Romain Guy
36746926698996d3857a650ed535024a88dbeaff1e1Romain Guy    @Override
36846926698996d3857a650ed535024a88dbeaff1e1Romain Guy    public boolean equals(Object o) {
36946926698996d3857a650ed535024a88dbeaff1e1Romain Guy        if (this == o) return true;
37046926698996d3857a650ed535024a88dbeaff1e1Romain Guy        if (o == null || getClass() != o.getClass()) return false;
37146926698996d3857a650ed535024a88dbeaff1e1Romain Guy
37246926698996d3857a650ed535024a88dbeaff1e1Romain Guy        Typeface typeface = (Typeface) o;
37346926698996d3857a650ed535024a88dbeaff1e1Romain Guy
37446926698996d3857a650ed535024a88dbeaff1e1Romain Guy        return mStyle == typeface.mStyle && native_instance == typeface.native_instance;
37546926698996d3857a650ed535024a88dbeaff1e1Romain Guy    }
37646926698996d3857a650ed535024a88dbeaff1e1Romain Guy
37746926698996d3857a650ed535024a88dbeaff1e1Romain Guy    @Override
37846926698996d3857a650ed535024a88dbeaff1e1Romain Guy    public int hashCode() {
37936bef0bf30d6bae48cf3837df351075ca4fce654Ashok Bhat        /*
38036bef0bf30d6bae48cf3837df351075ca4fce654Ashok Bhat         * Modified method for hashCode with long native_instance derived from
38136bef0bf30d6bae48cf3837df351075ca4fce654Ashok Bhat         * http://developer.android.com/reference/java/lang/Object.html
38236bef0bf30d6bae48cf3837df351075ca4fce654Ashok Bhat         */
38336bef0bf30d6bae48cf3837df351075ca4fce654Ashok Bhat        int result = 17;
38436bef0bf30d6bae48cf3837df351075ca4fce654Ashok Bhat        result = 31 * result + (int) (native_instance ^ (native_instance >>> 32));
38546926698996d3857a650ed535024a88dbeaff1e1Romain Guy        result = 31 * result + mStyle;
38646926698996d3857a650ed535024a88dbeaff1e1Romain Guy        return result;
3879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
38936bef0bf30d6bae48cf3837df351075ca4fce654Ashok Bhat    private static native long nativeCreateFromTypeface(long native_instance, int style);
390117cbebe810613d4a6de034f02652cdbbfef4cdeRaph Levien    private static native long nativeCreateWeightAlias(long native_instance, int weight);
39136bef0bf30d6bae48cf3837df351075ca4fce654Ashok Bhat    private static native void nativeUnref(long native_instance);
39236bef0bf30d6bae48cf3837df351075ca4fce654Ashok Bhat    private static native int  nativeGetStyle(long native_instance);
3931a73f732f91e97c9c66b808c245ddda36a10e987Raph Levien    private static native long nativeCreateFromArray(long[] familyArray);
3949a5b61ccc83303ceeec2059f58c1977af9faa9e3Raph Levien    private static native void nativeSetDefault(long native_instance);
3959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
396