Typeface.java revision 83ba4f9a04833409080d97480a665e029ee71365
1f62ea8018813951e8f6a182880cadb3217e4ce37Pawin Vongmasa/* 2f62ea8018813951e8f6a182880cadb3217e4ce37Pawin Vongmasa * Copyright (C) 2006 The Android Open Source Project 3f62ea8018813951e8f6a182880cadb3217e4ce37Pawin Vongmasa * 4f62ea8018813951e8f6a182880cadb3217e4ce37Pawin Vongmasa * Licensed under the Apache License, Version 2.0 (the "License"); 5f62ea8018813951e8f6a182880cadb3217e4ce37Pawin Vongmasa * you may not use this file except in compliance with the License. 6f62ea8018813951e8f6a182880cadb3217e4ce37Pawin Vongmasa * You may obtain a copy of the License at 7f62ea8018813951e8f6a182880cadb3217e4ce37Pawin Vongmasa * 8f62ea8018813951e8f6a182880cadb3217e4ce37Pawin Vongmasa * http://www.apache.org/licenses/LICENSE-2.0 9f62ea8018813951e8f6a182880cadb3217e4ce37Pawin Vongmasa * 10f62ea8018813951e8f6a182880cadb3217e4ce37Pawin Vongmasa * Unless required by applicable law or agreed to in writing, software 11f62ea8018813951e8f6a182880cadb3217e4ce37Pawin Vongmasa * distributed under the License is distributed on an "AS IS" BASIS, 12f62ea8018813951e8f6a182880cadb3217e4ce37Pawin Vongmasa * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13f62ea8018813951e8f6a182880cadb3217e4ce37Pawin Vongmasa * See the License for the specific language governing permissions and 14f62ea8018813951e8f6a182880cadb3217e4ce37Pawin Vongmasa * limitations under the License. 15f62ea8018813951e8f6a182880cadb3217e4ce37Pawin Vongmasa */ 16f62ea8018813951e8f6a182880cadb3217e4ce37Pawin Vongmasa 17517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasapackage android.graphics; 18517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa 19517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasaimport static android.content.res.FontResourcesParser.ProviderResourceEntry; 200d3a5edf232916e81adbc46fc0f4a1753166b066Pawin Vongmasaimport static android.content.res.FontResourcesParser.FontFileResourceEntry; 210d3a5edf232916e81adbc46fc0f4a1753166b066Pawin Vongmasaimport static android.content.res.FontResourcesParser.FontFamilyFilesResourceEntry; 220d3a5edf232916e81adbc46fc0f4a1753166b066Pawin Vongmasaimport static android.content.res.FontResourcesParser.FamilyResourceEntry; 230d3a5edf232916e81adbc46fc0f4a1753166b066Pawin Vongmasa 240d3a5edf232916e81adbc46fc0f4a1753166b066Pawin Vongmasaimport static java.lang.annotation.RetentionPolicy.SOURCE; 25517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa 26f62ea8018813951e8f6a182880cadb3217e4ce37Pawin Vongmasaimport android.annotation.IntDef; 27f62ea8018813951e8f6a182880cadb3217e4ce37Pawin Vongmasaimport android.annotation.IntRange; 28517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasaimport android.annotation.NonNull; 29f62ea8018813951e8f6a182880cadb3217e4ce37Pawin Vongmasaimport android.annotation.Nullable; 30f62ea8018813951e8f6a182880cadb3217e4ce37Pawin Vongmasaimport android.content.Context; 31f62ea8018813951e8f6a182880cadb3217e4ce37Pawin Vongmasaimport android.content.res.AssetManager; 32517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasaimport android.graphics.FontListParser; 33517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasaimport android.graphics.fonts.FontRequest; 3404563aafa0debc95d50951ca944abf37ef2777cePawin Vongmasaimport android.graphics.fonts.FontResult; 35ac7d4125516299b8a3e6f2b25822a692bdd96311Pawin Vongmasaimport android.graphics.fonts.FontVariationAxis; 360d3a5edf232916e81adbc46fc0f4a1753166b066Pawin Vongmasaimport android.graphics.fonts.FontVariationAxis.InvalidFormatException; 37ac7d4125516299b8a3e6f2b25822a692bdd96311Pawin Vongmasaimport android.net.Uri; 38517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasaimport android.os.Bundle; 390d3a5edf232916e81adbc46fc0f4a1753166b066Pawin Vongmasaimport android.os.Handler; 40517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasaimport android.os.ParcelFileDescriptor; 41517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasaimport android.os.ResultReceiver; 42517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasaimport android.provider.FontsContract; 43517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasaimport android.text.FontConfig; 44517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasaimport android.util.Base64; 45517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasaimport android.util.Log; 46517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasaimport android.util.LongSparseArray; 470d3a5edf232916e81adbc46fc0f4a1753166b066Pawin Vongmasaimport android.util.LruCache; 480d3a5edf232916e81adbc46fc0f4a1753166b066Pawin Vongmasaimport android.util.SparseArray; 490d3a5edf232916e81adbc46fc0f4a1753166b066Pawin Vongmasa 50517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasaimport com.android.internal.annotations.GuardedBy; 51517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasaimport com.android.internal.util.Preconditions; 52517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa 53517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasaimport libcore.io.IoUtils; 54517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa 55eeac97b18ca5c939bf2ac59334d36d54f705af3dPawin Vongmasaimport org.xmlpull.v1.XmlPullParserException; 56517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa 57517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasaimport java.io.File; 58517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasaimport java.io.FileDescriptor; 59517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasaimport java.io.FileInputStream; 60f62ea8018813951e8f6a182880cadb3217e4ce37Pawin Vongmasaimport java.io.FileNotFoundException; 61517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasaimport java.io.IOException; 62517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasaimport java.lang.annotation.Retention; 63517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasaimport java.lang.annotation.RetentionPolicy; 64517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasaimport java.nio.ByteBuffer; 65517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasaimport java.nio.channels.FileChannel; 66517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasaimport java.util.Arrays; 67517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasaimport java.util.ArrayList; 68517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasaimport java.util.Arrays; 69517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasaimport java.util.Collections; 70517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasaimport java.util.HashMap; 71517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasaimport java.util.List; 72f62ea8018813951e8f6a182880cadb3217e4ce37Pawin Vongmasaimport java.util.Map; 73f62ea8018813951e8f6a182880cadb3217e4ce37Pawin Vongmasaimport java.util.concurrent.atomic.AtomicReference; 74517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa 75517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa/** 76517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa * The Typeface class specifies the typeface and intrinsic style of a font. 77517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa * This is used in the paint, along with optionally Paint settings like 78517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa * textSize, textSkewX, textScaleX to specify 79517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa * how text appears when drawn (and measured). 80517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa */ 81f62ea8018813951e8f6a182880cadb3217e4ce37Pawin Vongmasapublic class Typeface { 82f62ea8018813951e8f6a182880cadb3217e4ce37Pawin Vongmasa 83f62ea8018813951e8f6a182880cadb3217e4ce37Pawin Vongmasa private static String TAG = "Typeface"; 84517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa 85517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa /** The default NORMAL typeface object */ 86517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa public static final Typeface DEFAULT; 87517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa /** 88517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa * The default BOLD typeface object. Note: this may be not actually be 89517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa * bold, depending on what fonts are installed. Call getStyle() to know 90517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa * for sure. 91517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa */ 92517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa public static final Typeface DEFAULT_BOLD; 93517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa /** The NORMAL style of the default sans serif typeface. */ 94517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa public static final Typeface SANS_SERIF; 95517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa /** The NORMAL style of the default serif typeface. */ 96517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa public static final Typeface SERIF; 97517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa /** The NORMAL style of the default monospace typeface. */ 98517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa public static final Typeface MONOSPACE; 99517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa 100517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa static Typeface[] sDefaults; 101517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa private static final LongSparseArray<SparseArray<Typeface>> sTypefaceCache = 102517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa new LongSparseArray<>(3); 103517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa @GuardedBy("sLock") 104517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa private static FontsContract sFontsContract; 105517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa @GuardedBy("sLock") 106517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa private static Handler sHandler; 107517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa 108517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa /** 109517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa * Cache for Typeface objects dynamically loaded from assets. Currently max size is 16. 110517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa */ 111517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa @GuardedBy("sLock") 112517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa private static final LruCache<String, Typeface> sDynamicTypefaceCache = new LruCache<>(16); 113517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa 114517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa static Typeface sDefaultTypeface; 115517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa static Map<String, Typeface> sSystemFontMap; 116517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa static FontFamily[] sFallbackFonts; 117517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa private static final Object sLock = new Object(); 118517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa 119517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa static final String FONTS_CONFIG = "fonts.xml"; 120517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa 121517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa /** 122517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa * @hide 123517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa */ 124517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa public long native_instance; 125517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa 126517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa // Style 127517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa public static final int NORMAL = 0; 128517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa public static final int BOLD = 1; 129517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa public static final int ITALIC = 2; 130517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa public static final int BOLD_ITALIC = 3; 131517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa 132517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa private int mStyle = 0; 133517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa private int mBaseWeight = 0; 134517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa 135517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa // Value for weight and italic. Indicates the value is resolved by font metadata. 136517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa // Must be the same as the C++ constant in core/jni/android/graphics/FontFamily.cpp 137517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa /** @hide */ 138517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa public static final int RESOLVE_BY_FONT_TABLE = -1; 139517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa 140517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa // Style value for building typeface. 141517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa private static final int STYLE_NORMAL = 0; 142517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa private static final int STYLE_ITALIC = 1; 143517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa 144517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa private int[] mSupportedAxes; 145517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa private static final int[] EMPTY_AXES = {}; 146517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa 147517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa private static void setDefault(Typeface t) { 148517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa sDefaultTypeface = t; 149517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa nativeSetDefault(t.native_instance); 150517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa } 151517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa 152517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa /** Returns the typeface's intrinsic style attributes */ 153517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa public int getStyle() { 154517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa return mStyle; 155517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa } 156517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa 157517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa /** Returns true if getStyle() has the BOLD bit set. */ 158517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa public final boolean isBold() { 159517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa return (mStyle & BOLD) != 0; 160517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa } 161517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa 162517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa /** Returns true if getStyle() has the ITALIC bit set. */ 163517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa public final boolean isItalic() { 164517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa return (mStyle & ITALIC) != 0; 165517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa } 166517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa 167517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa /** 168517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa * @hide 169517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa * Used by Resources to load a font resource of type font file. 170517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa */ 171517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa @Nullable 172517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa public static Typeface createFromResources(AssetManager mgr, String path, int cookie) { 173517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa if (sFallbackFonts != null) { 174517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa synchronized (sDynamicTypefaceCache) { 175e83be8af690ef1ac820a63414d522e77ca9d4db6Steven Moreland final String key = Builder.createAssetUid( 176517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa mgr, path, 0 /* ttcIndex */, null /* axes */, 177e83be8af690ef1ac820a63414d522e77ca9d4db6Steven Moreland RESOLVE_BY_FONT_TABLE /* weight */, RESOLVE_BY_FONT_TABLE /* italic */); 178517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa Typeface typeface = sDynamicTypefaceCache.get(key); 179517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa if (typeface != null) return typeface; 180e83be8af690ef1ac820a63414d522e77ca9d4db6Steven Moreland 181517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa FontFamily fontFamily = new FontFamily(); 182e83be8af690ef1ac820a63414d522e77ca9d4db6Steven Moreland // TODO: introduce ttc index and variation settings to resource type font. 183517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa if (fontFamily.addFontFromAssetManager(mgr, path, cookie, false /* isAsset */, 184e83be8af690ef1ac820a63414d522e77ca9d4db6Steven Moreland 0 /* ttcIndex */, RESOLVE_BY_FONT_TABLE /* weight */, 185e83be8af690ef1ac820a63414d522e77ca9d4db6Steven Moreland RESOLVE_BY_FONT_TABLE /* italic */, null /* axes */)) { 186517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa if (!fontFamily.freeze()) { 187517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa return null; 188517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa } 189d095e65c8c125c555046c60539a0f7abf0ccf271Robert Shih FontFamily[] families = {fontFamily}; 190d095e65c8c125c555046c60539a0f7abf0ccf271Robert Shih typeface = createFromFamiliesWithDefault(families, 191d095e65c8c125c555046c60539a0f7abf0ccf271Robert Shih RESOLVE_BY_FONT_TABLE, RESOLVE_BY_FONT_TABLE); 192d095e65c8c125c555046c60539a0f7abf0ccf271Robert Shih sDynamicTypefaceCache.put(key, typeface); 193d095e65c8c125c555046c60539a0f7abf0ccf271Robert Shih return typeface; 194d095e65c8c125c555046c60539a0f7abf0ccf271Robert Shih } 195d095e65c8c125c555046c60539a0f7abf0ccf271Robert Shih } 196d095e65c8c125c555046c60539a0f7abf0ccf271Robert Shih } 197d095e65c8c125c555046c60539a0f7abf0ccf271Robert Shih return null; 198d095e65c8c125c555046c60539a0f7abf0ccf271Robert Shih } 199d095e65c8c125c555046c60539a0f7abf0ccf271Robert Shih 200d095e65c8c125c555046c60539a0f7abf0ccf271Robert Shih /** 201d095e65c8c125c555046c60539a0f7abf0ccf271Robert Shih * @hide 202517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa * Used by Resources to load a font resource of type xml. 203517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa */ 204517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa @Nullable 205517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa public static Typeface createFromResources( 206517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa FamilyResourceEntry entry, AssetManager mgr, String path) { 207517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa if (sFallbackFonts != null) { 208517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa Typeface typeface = findFromCache(mgr, path); 209517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa if (typeface != null) return typeface; 210517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa 211517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa if (entry instanceof ProviderResourceEntry) { 212517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa final ProviderResourceEntry providerEntry = (ProviderResourceEntry) entry; 213517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa // Downloadable font 214517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa typeface = findFromCache(providerEntry.getAuthority(), providerEntry.getQuery()); 215517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa if (typeface != null) { 216517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa return typeface; 217517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa } 218e83be8af690ef1ac820a63414d522e77ca9d4db6Steven Moreland List<List<String>> givenCerts = providerEntry.getCerts(); 219517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa List<List<byte[]>> certs = new ArrayList<>(); 220517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa if (givenCerts != null) { 221517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa for (int i = 0; i < givenCerts.size(); i++) { 222517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa List<String> certSet = givenCerts.get(i); 223517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa List<byte[]> byteArraySet = new ArrayList<>(); 224517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa for (int j = 0; j < certSet.size(); j++) { 225517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa byteArraySet.add(Base64.decode(certSet.get(j), Base64.DEFAULT)); 226517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa } 227517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa certs.add(byteArraySet); 228517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa } 229e83be8af690ef1ac820a63414d522e77ca9d4db6Steven Moreland } 230517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa // Downloaded font and it wasn't cached, request it again and return a 231517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa // default font instead (nothing we can do now). 232517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa create(new FontRequest(providerEntry.getAuthority(), providerEntry.getPackage(), 233517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa providerEntry.getQuery(), certs), NO_OP_REQUEST_CALLBACK); 234517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa return DEFAULT; 235517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa } 236517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa 237517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa // family is FontFamilyFilesResourceEntry 238517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa final FontFamilyFilesResourceEntry filesEntry = 239517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa (FontFamilyFilesResourceEntry) entry; 240517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa 241517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa FontFamily fontFamily = new FontFamily(); 242517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa for (final FontFileResourceEntry fontFile : filesEntry.getEntries()) { 243517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa if (!fontFamily.addFontFromAssetManager(mgr, fontFile.getFileName(), 244517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa 0 /* resourceCookie */, false /* isAsset */, 0 /* ttcIndex */, 245517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa fontFile.getWeight(), fontFile.isItalic() ? STYLE_ITALIC : STYLE_NORMAL, 246517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa null /* axes */)) { 247517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa return null; 248517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa } 249517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa } 250517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa // Due to backward compatibility, even if the font is not supported by our font stack, 251517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa // we need to place the empty font at the first place. The typeface with empty font 252517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa // behaves different from default typeface especially in fallback font selection. 253517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa fontFamily.allowUnsupportedFont(); 254517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa fontFamily.freeze(); 255517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa FontFamily[] familyChain = { fontFamily }; 256517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa typeface = createFromFamiliesWithDefault(familyChain, 257517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa RESOLVE_BY_FONT_TABLE, RESOLVE_BY_FONT_TABLE); 258517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa synchronized (sDynamicTypefaceCache) { 259517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa final String key = Builder.createAssetUid(mgr, path, 0 /* ttcIndex */, 260517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa null /* axes */, RESOLVE_BY_FONT_TABLE /* weight */, 261517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa RESOLVE_BY_FONT_TABLE /* italic */); 262517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa sDynamicTypefaceCache.put(key, typeface); 263517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa } 264517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa return typeface; 265517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa } 266517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa return null; 267517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa } 268517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa 269517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa /** 270517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa * Used by resources for cached loading if the font is available. 271517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa * @hide 272517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa */ 273517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa public static Typeface findFromCache(AssetManager mgr, String path) { 274517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa synchronized (sDynamicTypefaceCache) { 275517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa final String key = Builder.createAssetUid(mgr, path, 0 /* ttcIndex */, null /* axes */, 276517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa RESOLVE_BY_FONT_TABLE /* weight */, RESOLVE_BY_FONT_TABLE /* italic */); 277517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa Typeface typeface = sDynamicTypefaceCache.get(key); 278517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa if (typeface != null) { 279517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa return typeface; 280517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa } 281517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa } 282517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa return null; 283517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa } 284517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa 285517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa /** 2868ff40189817e95c7a56e347398d20e60d7534ee6Pawin Vongmasa * Set the application context so we can generate font requests from the provider. This should 287517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa * be called from ActivityThread when the application binds, as we preload fonts. 288517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa * @hide 289517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa */ 2908a21c0191f974a0b9cbd5818052e2655e0aaa306Pawin Vongmasa public static void setApplicationContext(Context context) { 291517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa synchronized (sLock) { 292517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa if (sFontsContract == null) { 293517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa sFontsContract = new FontsContract(context); 294517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa sHandler = new Handler(); 295517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa } 296517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa } 297517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa } 298517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa 299517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa /** 300517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa * Create a typeface object given a font request. The font will be asynchronously fetched, 301517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa * therefore the result is delivered to the given callback. See {@link FontRequest}. 302517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa * Only one of the methods in callback will be invoked, depending on whether the request 303f62ea8018813951e8f6a182880cadb3217e4ce37Pawin Vongmasa * succeeds or fails. These calls will happen on the main thread. 304f62ea8018813951e8f6a182880cadb3217e4ce37Pawin Vongmasa * @param request A {@link FontRequest} object that identifies the provider and query for the 305f62ea8018813951e8f6a182880cadb3217e4ce37Pawin Vongmasa * request. May not be null. 306f62ea8018813951e8f6a182880cadb3217e4ce37Pawin Vongmasa * @param callback A callback that will be triggered when results are obtained. May not be null. 307517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa */ 308f62ea8018813951e8f6a182880cadb3217e4ce37Pawin Vongmasa @Deprecated 309f62ea8018813951e8f6a182880cadb3217e4ce37Pawin Vongmasa public static void create(@NonNull FontRequest request, @NonNull FontRequestCallback callback) { 310517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa // Check the cache first 311517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa // TODO: would the developer want to avoid a cache hit and always ask for the freshest 312517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa // result? 313517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa Typeface cachedTypeface = findFromCache( 314517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa request.getProviderAuthority(), request.getQuery()); 315517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa if (cachedTypeface != null) { 316517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa sHandler.post(() -> callback.onTypefaceRetrieved(cachedTypeface)); 317517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa return; 318517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa } 319517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa synchronized (sLock) { 320517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa if (sFontsContract == null) { 321517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa throw new RuntimeException("Context not initialized, can't query provider"); 322517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa } 323517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa final ResultReceiver receiver = new ResultReceiver(null) { 324517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa @Override 325517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa public void onReceiveResult(int resultCode, Bundle resultData) { 326517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa sHandler.post(() -> receiveResult(request, callback, resultCode, resultData)); 327517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa } 328517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa }; 329517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa sFontsContract.getFont(request, receiver); 330517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa } 331517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa } 332517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa 333517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa private static Typeface findFromCache(String providerAuthority, String query) { 334517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa synchronized (sDynamicTypefaceCache) { 335517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa final String key = createProviderUid(providerAuthority, query); 3368a21c0191f974a0b9cbd5818052e2655e0aaa306Pawin Vongmasa Typeface typeface = sDynamicTypefaceCache.get(key); 337517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa if (typeface != null) { 338517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa return typeface; 339517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa } 340517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa } 341517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa return null; 342517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa } 343517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa 344517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa private static void receiveResult(FontRequest request, FontRequestCallback callback, 345517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa int resultCode, Bundle resultData) { 346517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa Typeface cachedTypeface = findFromCache( 347517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa request.getProviderAuthority(), request.getQuery()); 348517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa if (cachedTypeface != null) { 349f62ea8018813951e8f6a182880cadb3217e4ce37Pawin Vongmasa // We already know the result. 350f62ea8018813951e8f6a182880cadb3217e4ce37Pawin Vongmasa // Probably the requester requests the same font again in a short interval. 351f62ea8018813951e8f6a182880cadb3217e4ce37Pawin Vongmasa callback.onTypefaceRetrieved(cachedTypeface); 352f62ea8018813951e8f6a182880cadb3217e4ce37Pawin Vongmasa return; 353517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa } 354f62ea8018813951e8f6a182880cadb3217e4ce37Pawin Vongmasa if (resultCode != FontsContract.Columns.RESULT_CODE_OK) { 355f62ea8018813951e8f6a182880cadb3217e4ce37Pawin Vongmasa callback.onTypefaceRequestFailed(resultCode); 356517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa return; 357517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa } 358517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa if (resultData == null) { 359517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa callback.onTypefaceRequestFailed( 360517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa FontRequestCallback.FAIL_REASON_FONT_NOT_FOUND); 361517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa return; 362517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa } 363517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa List<FontResult> resultList = 364517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa resultData.getParcelableArrayList(FontsContract.PARCEL_FONT_RESULTS); 365517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa if (resultList == null || resultList.isEmpty()) { 366517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa callback.onTypefaceRequestFailed( 367517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa FontRequestCallback.FAIL_REASON_FONT_NOT_FOUND); 368517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa return; 369517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa } 370517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa FontFamily fontFamily = new FontFamily(); 371517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa for (int i = 0; i < resultList.size(); ++i) { 372517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa FontResult result = resultList.get(i); 373517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa ParcelFileDescriptor fd = result.getFileDescriptor(); 374517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa if (fd == null) { 375517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa callback.onTypefaceRequestFailed( 376f62ea8018813951e8f6a182880cadb3217e4ce37Pawin Vongmasa FontRequestCallback.FAIL_REASON_FONT_LOAD_ERROR); 377f62ea8018813951e8f6a182880cadb3217e4ce37Pawin Vongmasa return; 378f62ea8018813951e8f6a182880cadb3217e4ce37Pawin Vongmasa } 379517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa try (FileInputStream is = new FileInputStream(fd.getFileDescriptor())) { 380517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa FileChannel fileChannel = is.getChannel(); 381517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa long fontSize = fileChannel.size(); 382517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa ByteBuffer fontBuffer = fileChannel.map( 383517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa FileChannel.MapMode.READ_ONLY, 0, fontSize); 384517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa int weight = result.getWeight(); 385517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa int italic = result.getItalic() ? STYLE_ITALIC : STYLE_NORMAL; 386517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa FontVariationAxis[] axes = null; 387517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa try { 388517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa axes = FontVariationAxis.fromFontVariationSettings( 389517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa result.getFontVariationSettings()); 390517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa } catch (FontVariationAxis.InvalidFormatException e) { 391517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa // TODO: Nice to pass FontVariationAxis[] directly instead of string. 392517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa } 393517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa if (!fontFamily.addFontFromBuffer(fontBuffer, result.getTtcIndex(), 394517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa axes, weight, italic)) { 395517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa Log.e(TAG, "Error creating font " + request.getQuery()); 396517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa callback.onTypefaceRequestFailed( 397517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa FontRequestCallback.FAIL_REASON_FONT_LOAD_ERROR); 398517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa return; 399517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa } 400517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa } catch (IOException e) { 401517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa Log.e(TAG, "Error reading font " + request.getQuery(), e); 402517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa callback.onTypefaceRequestFailed( 403517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa FontRequestCallback.FAIL_REASON_FONT_LOAD_ERROR); 404517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa return; 405517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa } finally { 406517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa IoUtils.closeQuietly(fd); 407517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa } 408517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa } 409517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa if (!fontFamily.freeze()) { 410517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa callback.onTypefaceRequestFailed( 411517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa FontRequestCallback.FAIL_REASON_FONT_LOAD_ERROR); 412517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa return; 413517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa } 414517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa Typeface typeface = Typeface.createFromFamiliesWithDefault( 415517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa new FontFamily[] { fontFamily }, 416517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa RESOLVE_BY_FONT_TABLE, RESOLVE_BY_FONT_TABLE); 417517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa synchronized (sDynamicTypefaceCache) { 418517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa String key = createProviderUid(request.getProviderAuthority(), request.getQuery()); 419517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa sDynamicTypefaceCache.put(key, typeface); 420517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa } 421517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa callback.onTypefaceRetrieved(typeface); 422517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa } 423517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa 424517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa /** 425517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa * Interface used to receive asynchronously fetched typefaces. 426517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa */ 427517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa @Deprecated 428517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa public interface FontRequestCallback { 429517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa /** 430517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa * Constant returned by {@link #onTypefaceRequestFailed(int)} signaling that the given 431517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa * provider was not found on the device. 432517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa */ 433517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa int FAIL_REASON_PROVIDER_NOT_FOUND = FontsContract.RESULT_CODE_PROVIDER_NOT_FOUND; 434517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa /** 435517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa * Constant returned by {@link #onTypefaceRequestFailed(int)} signaling that the given 436517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa * provider must be authenticated and the given certificates do not match its signature. 437517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa */ 438517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa int FAIL_REASON_WRONG_CERTIFICATES = FontsContract.RESULT_CODE_WRONG_CERTIFICATES; 439517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa /** 440517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa * Constant returned by {@link #onTypefaceRequestFailed(int)} signaling that the font 441517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa * returned by the provider was not loaded properly. 442517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa */ 443517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa int FAIL_REASON_FONT_LOAD_ERROR = -3; 444517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa /** 445517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa * Constant returned by {@link #onTypefaceRequestFailed(int)} signaling that the font 446517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa * provider did not return any results for the given query. 447517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa */ 448517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa int FAIL_REASON_FONT_NOT_FOUND = FontsContract.Columns.RESULT_CODE_FONT_NOT_FOUND; 449517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa /** 450517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa * Constant returned by {@link #onTypefaceRequestFailed(int)} signaling that the font 451517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa * provider found the queried font, but it is currently unavailable. 452517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa */ 453517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa int FAIL_REASON_FONT_UNAVAILABLE = FontsContract.Columns.RESULT_CODE_FONT_UNAVAILABLE; 454517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa /** 455517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa * Constant returned by {@link #onTypefaceRequestFailed(int)} signaling that the given 456517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa * query was not supported by the provider. 457517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa */ 458517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa int FAIL_REASON_MALFORMED_QUERY = FontsContract.Columns.RESULT_CODE_MALFORMED_QUERY; 459517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa 460517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa /** @hide */ 461517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa @IntDef({ FAIL_REASON_PROVIDER_NOT_FOUND, FAIL_REASON_FONT_LOAD_ERROR, 462517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa FAIL_REASON_FONT_NOT_FOUND, FAIL_REASON_FONT_UNAVAILABLE, 463517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa FAIL_REASON_MALFORMED_QUERY }) 464517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa @Retention(RetentionPolicy.SOURCE) 465517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa @interface FontRequestFailReason {} 466517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa 467517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa /** 468517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa * Called then a Typeface request done via {@link Typeface#create(FontRequest, 469517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa * FontRequestCallback)} is complete. Note that this method will not be called if 470517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa * {@link #onTypefaceRequestFailed(int)} is called instead. 471517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa * @param typeface The Typeface object retrieved. 472517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa */ 473517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa void onTypefaceRetrieved(Typeface typeface); 474517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa 475517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa /** 476517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa * Called when a Typeface request done via {@link Typeface#create(FontRequest, 477517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa * FontRequestCallback)} fails. 478517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa * @param reason One of {@link #FAIL_REASON_PROVIDER_NOT_FOUND}, 479517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa * {@link #FAIL_REASON_FONT_NOT_FOUND}, 480517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa * {@link #FAIL_REASON_FONT_LOAD_ERROR}, 481517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa * {@link #FAIL_REASON_FONT_UNAVAILABLE} or 482517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa * {@link #FAIL_REASON_MALFORMED_QUERY}. 483517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa */ 484517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa void onTypefaceRequestFailed(@FontRequestFailReason int reason); 485517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa } 486517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa 487517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa private static final FontRequestCallback NO_OP_REQUEST_CALLBACK = new FontRequestCallback() { 488517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa @Override 489517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa public void onTypefaceRetrieved(Typeface typeface) { 490517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa // Do nothing. 491517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa } 492517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa 493517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa @Override 494517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa public void onTypefaceRequestFailed(@FontRequestFailReason int reason) { 495517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa // Do nothing. 496517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa } 497517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa }; 498517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa 499517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa /** 500517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa * A builder class for creating new Typeface instance. 501517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa * 502517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa * <p> 503517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa * Examples, 504517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa * 1) Create Typeface from ttf file. 505517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa * <pre> 506517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa * <code> 507517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa * Typeface.Builder buidler = new Typeface.Builder("your_font_file.ttf"); 508517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa * Typeface typeface = builder.build(); 509517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa * </code> 510517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa * </pre> 511517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa * 512517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa * 2) Create Typeface from ttc file in assets directory. 513517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa * <pre> 514517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa * <code> 515517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa * Typeface.Builder buidler = new Typeface.Builder(getAssets(), "your_font_file.ttc"); 516517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa * builder.setTtcIndex(2); // Set index of font collection. 517517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa * Typeface typeface = builder.build(); 518517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa * </code> 519517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa * </pre> 520517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa * 521517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa * 3) Create Typeface with variation settings. 522517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa * <pre> 523517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa * <code> 524517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa * Typeface.Builder buidler = new Typeface.Builder("your_font_file.ttf"); 525517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa * builder.setFontVariationSettings("'wght' 700, 'slnt' 20, 'ital' 1"); 526517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa * builder.setWeight(700); // Tell the system that this is a bold font. 527517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa * builder.setItalic(true); // Tell the system that this is an italic style font. 528517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa * Typeface typeface = builder.build(); 529517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa * </code> 530517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa * </pre> 531517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa * </p> 532517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa */ 533517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa public static final class Builder { 534517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa /** @hide */ 535517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa public static final int NORMAL_WEIGHT = 400; 536517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa /** @hide */ 537517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa public static final int BOLD_WEIGHT = 700; 538517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa 539517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa private int mTtcIndex; 540517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa private FontVariationAxis[] mAxes; 541517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa 542517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa private AssetManager mAssetManager; 543517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa private String mPath; 544517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa private FileDescriptor mFd; 545517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa 546517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa private FontsContract.FontInfo[] mFonts; 547517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa private Map<Uri, ByteBuffer> mFontBuffers; 548517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa 549517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa private String mFallbackFamilyName; 550517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa 551517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa private int mWeight = RESOLVE_BY_FONT_TABLE; 5529c47c97ecac581d66b6febafd156618247e86742Pawin Vongmasa private int mItalic = RESOLVE_BY_FONT_TABLE; 5539c47c97ecac581d66b6febafd156618247e86742Pawin Vongmasa 5549c47c97ecac581d66b6febafd156618247e86742Pawin Vongmasa /** 5559c47c97ecac581d66b6febafd156618247e86742Pawin Vongmasa * Constructs a builder with a file path. 5569c47c97ecac581d66b6febafd156618247e86742Pawin Vongmasa * 5579c47c97ecac581d66b6febafd156618247e86742Pawin Vongmasa * @param path The file object refers to the font file. 5589c47c97ecac581d66b6febafd156618247e86742Pawin Vongmasa */ 5599c47c97ecac581d66b6febafd156618247e86742Pawin Vongmasa public Builder(@NonNull File path) { 5609c47c97ecac581d66b6febafd156618247e86742Pawin Vongmasa mPath = path.getAbsolutePath(); 5619c47c97ecac581d66b6febafd156618247e86742Pawin Vongmasa } 5629c47c97ecac581d66b6febafd156618247e86742Pawin Vongmasa 5639c47c97ecac581d66b6febafd156618247e86742Pawin Vongmasa /** 5649c47c97ecac581d66b6febafd156618247e86742Pawin Vongmasa * Constructs a builder with a file descriptor. 5659c47c97ecac581d66b6febafd156618247e86742Pawin Vongmasa * 5669c47c97ecac581d66b6febafd156618247e86742Pawin Vongmasa * Caller is responsible for closing the passed file descriptor after {@link #build} is 5679c47c97ecac581d66b6febafd156618247e86742Pawin Vongmasa * called. 5689c47c97ecac581d66b6febafd156618247e86742Pawin Vongmasa * 5699c47c97ecac581d66b6febafd156618247e86742Pawin Vongmasa * @param fd The file descriptor. The passed fd must be mmap-able. 5709c47c97ecac581d66b6febafd156618247e86742Pawin Vongmasa */ 5719c47c97ecac581d66b6febafd156618247e86742Pawin Vongmasa public Builder(@NonNull FileDescriptor fd) { 5729c47c97ecac581d66b6febafd156618247e86742Pawin Vongmasa mFd = fd; 5739c47c97ecac581d66b6febafd156618247e86742Pawin Vongmasa } 5749c47c97ecac581d66b6febafd156618247e86742Pawin Vongmasa 5759c47c97ecac581d66b6febafd156618247e86742Pawin Vongmasa /** 5769c47c97ecac581d66b6febafd156618247e86742Pawin Vongmasa * Constructs a builder with a file path. 5779c47c97ecac581d66b6febafd156618247e86742Pawin Vongmasa * 5789c47c97ecac581d66b6febafd156618247e86742Pawin Vongmasa * @param path The full path to the font file. 5799c47c97ecac581d66b6febafd156618247e86742Pawin Vongmasa */ 5809c47c97ecac581d66b6febafd156618247e86742Pawin Vongmasa public Builder(@NonNull String path) { 5819c47c97ecac581d66b6febafd156618247e86742Pawin Vongmasa mPath = path; 5829c47c97ecac581d66b6febafd156618247e86742Pawin Vongmasa } 5839c47c97ecac581d66b6febafd156618247e86742Pawin Vongmasa 5849c47c97ecac581d66b6febafd156618247e86742Pawin Vongmasa /** 5859c47c97ecac581d66b6febafd156618247e86742Pawin Vongmasa * Constructs a builder from an asset manager and a file path in an asset directory. 5869c47c97ecac581d66b6febafd156618247e86742Pawin Vongmasa * 5879c47c97ecac581d66b6febafd156618247e86742Pawin Vongmasa * @param assetManager The application's asset manager 5889c47c97ecac581d66b6febafd156618247e86742Pawin Vongmasa * @param path The file name of the font data in the asset directory 5899c47c97ecac581d66b6febafd156618247e86742Pawin Vongmasa */ 5909c47c97ecac581d66b6febafd156618247e86742Pawin Vongmasa public Builder(@NonNull AssetManager assetManager, @NonNull String path) { 5919c47c97ecac581d66b6febafd156618247e86742Pawin Vongmasa mAssetManager = Preconditions.checkNotNull(assetManager); 5929c47c97ecac581d66b6febafd156618247e86742Pawin Vongmasa mPath = Preconditions.checkStringNotEmpty(path); 5939c47c97ecac581d66b6febafd156618247e86742Pawin Vongmasa } 5949c47c97ecac581d66b6febafd156618247e86742Pawin Vongmasa 5959c47c97ecac581d66b6febafd156618247e86742Pawin Vongmasa /** 5969c47c97ecac581d66b6febafd156618247e86742Pawin Vongmasa * Constracts a builder from an array of FontsContract.FontInfo. 5979c47c97ecac581d66b6febafd156618247e86742Pawin Vongmasa * 5989c47c97ecac581d66b6febafd156618247e86742Pawin Vongmasa * Since {@link FontsContract.FontInfo} holds information about TTC indices and 5999c47c97ecac581d66b6febafd156618247e86742Pawin Vongmasa * variation settings, there is no need to call {@link #setTtcIndex} or 6009c47c97ecac581d66b6febafd156618247e86742Pawin Vongmasa * {@link #setFontVariationSettings}. Similary, {@link FontsContract.FontInfo} holds 6019c47c97ecac581d66b6febafd156618247e86742Pawin Vongmasa * weight and italic information, so {@link #setWeight} and {@link #setItalic} are used 6029c47c97ecac581d66b6febafd156618247e86742Pawin Vongmasa * for style matching during font selection. 6039c47c97ecac581d66b6febafd156618247e86742Pawin Vongmasa * 6049c47c97ecac581d66b6febafd156618247e86742Pawin Vongmasa * @param results The array of {@link FontsContract.FontInfo} 6059c47c97ecac581d66b6febafd156618247e86742Pawin Vongmasa * @param buffers The mapping from URI to buffers to be used during building. 6069c47c97ecac581d66b6febafd156618247e86742Pawin Vongmasa * @hide 6079c47c97ecac581d66b6febafd156618247e86742Pawin Vongmasa */ 6089c47c97ecac581d66b6febafd156618247e86742Pawin Vongmasa public Builder(@NonNull FontsContract.FontInfo[] fonts, 6099c47c97ecac581d66b6febafd156618247e86742Pawin Vongmasa @NonNull Map<Uri, ByteBuffer> buffers) { 6109c47c97ecac581d66b6febafd156618247e86742Pawin Vongmasa mFonts = fonts; 6119c47c97ecac581d66b6febafd156618247e86742Pawin Vongmasa mFontBuffers = buffers; 6129c47c97ecac581d66b6febafd156618247e86742Pawin Vongmasa } 6139c47c97ecac581d66b6febafd156618247e86742Pawin Vongmasa 6149c47c97ecac581d66b6febafd156618247e86742Pawin Vongmasa /** 6159c47c97ecac581d66b6febafd156618247e86742Pawin Vongmasa * Sets weight of the font. 6169c47c97ecac581d66b6febafd156618247e86742Pawin Vongmasa * 6179c47c97ecac581d66b6febafd156618247e86742Pawin Vongmasa * Tells the system the weight of the given font. If not provided, the system will resolve 6189c47c97ecac581d66b6febafd156618247e86742Pawin Vongmasa * the weight value by reading font tables. 6199c47c97ecac581d66b6febafd156618247e86742Pawin Vongmasa * @param weight a weight value. 6209c47c97ecac581d66b6febafd156618247e86742Pawin Vongmasa */ 6219c47c97ecac581d66b6febafd156618247e86742Pawin Vongmasa public Builder setWeight(@IntRange(from = 1, to = 1000) int weight) { 622517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa mWeight = weight; 623517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa return this; 624517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa } 625517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa 626517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa /** 627517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa * Sets italic information of the font. 628517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa * 629517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa * Tells the system the style of the given font. If not provided, the system will resolve 630f62ea8018813951e8f6a182880cadb3217e4ce37Pawin Vongmasa * the style by reading font tables. 6319c47c97ecac581d66b6febafd156618247e86742Pawin Vongmasa * @param italic {@code true} if the font is italic. Otherwise {@code false}. 632517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa */ 633517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa public Builder setItalic(boolean italic) { 634517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa mItalic = italic ? STYLE_ITALIC : STYLE_NORMAL; 635517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa return this; 636517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa } 637517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa 638517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa /** 639517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa * Sets an index of the font collection. 640f62ea8018813951e8f6a182880cadb3217e4ce37Pawin Vongmasa * 641517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa * Can not be used for Typeface source. build() method will return null for invalid index. 642517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa * @param ttcIndex An index of the font collection. If the font source is not font 643f62ea8018813951e8f6a182880cadb3217e4ce37Pawin Vongmasa * collection, do not call this method or specify 0. 644517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa */ 645f62ea8018813951e8f6a182880cadb3217e4ce37Pawin Vongmasa public Builder setTtcIndex(@IntRange(from = 0) int ttcIndex) { 646f62ea8018813951e8f6a182880cadb3217e4ce37Pawin Vongmasa if (mFonts != null) { 647f62ea8018813951e8f6a182880cadb3217e4ce37Pawin Vongmasa throw new IllegalArgumentException( 648f62ea8018813951e8f6a182880cadb3217e4ce37Pawin Vongmasa "TTC index can not be specified for FontResult source."); 649f62ea8018813951e8f6a182880cadb3217e4ce37Pawin Vongmasa } 650517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa mTtcIndex = ttcIndex; 651517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa return this; 652517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa } 653517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa 6548ff40189817e95c7a56e347398d20e60d7534ee6Pawin Vongmasa /** 6558ff40189817e95c7a56e347398d20e60d7534ee6Pawin Vongmasa * Sets a font variation settings. 6568ff40189817e95c7a56e347398d20e60d7534ee6Pawin Vongmasa * 6578ff40189817e95c7a56e347398d20e60d7534ee6Pawin Vongmasa * @param variationSettings See {@link android.widget.TextView#setFontVariationSettings}. 6588ff40189817e95c7a56e347398d20e60d7534ee6Pawin Vongmasa * @throws InvalidFormatException If given string is not a valid font variation settings 6598ff40189817e95c7a56e347398d20e60d7534ee6Pawin Vongmasa * format. 6608ff40189817e95c7a56e347398d20e60d7534ee6Pawin Vongmasa */ 6618ff40189817e95c7a56e347398d20e60d7534ee6Pawin Vongmasa public Builder setFontVariationSettings(@Nullable String variationSettings) 6628ff40189817e95c7a56e347398d20e60d7534ee6Pawin Vongmasa throws InvalidFormatException { 663517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa if (mFonts != null) { 664517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa throw new IllegalArgumentException( 665517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa "Font variation settings can not be specified for FontResult source."); 666f62ea8018813951e8f6a182880cadb3217e4ce37Pawin Vongmasa } 667f62ea8018813951e8f6a182880cadb3217e4ce37Pawin Vongmasa if (mAxes != null) { 668517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa throw new IllegalStateException("Font variation settings are already set."); 669517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa } 6709c47c97ecac581d66b6febafd156618247e86742Pawin Vongmasa mAxes = FontVariationAxis.fromFontVariationSettings(variationSettings); 671517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa return this; 672517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa } 673517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa 674517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa /** 6759c47c97ecac581d66b6febafd156618247e86742Pawin Vongmasa * Sets a font variation settings. 676517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa * 677517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa * @param axes An array of font variation axis tag-value pairs. 678517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa */ 679517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa public Builder setFontVariationSettings(@Nullable FontVariationAxis[] axes) { 680517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa if (mFonts != null) { 681517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa throw new IllegalArgumentException( 682517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa "Font variation settings can not be specified for FontResult source."); 683517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa } 684517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa if (mAxes != null) { 685517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa throw new IllegalStateException("Font variation settings are already set."); 686517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa } 687517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa mAxes = axes; 688517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa return this; 689517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa } 690517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa 691517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa /** 692517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa * Sets a fallback family name. 693517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa * 694517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa * By specifying a fallback family name, a fallback Typeface will be returned if the 695517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa * {@link #build} method fails to create a Typeface from the provided font. The fallback 696517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa * family will be resolved with the provided weight and italic information specified by 697f62ea8018813951e8f6a182880cadb3217e4ce37Pawin Vongmasa * {@link #setWeight} and {@link #setItalic}. 698f62ea8018813951e8f6a182880cadb3217e4ce37Pawin Vongmasa * 699f62ea8018813951e8f6a182880cadb3217e4ce37Pawin Vongmasa * If {@link #setWeight} is not called, the fallback family keeps the default weight. 700517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa * Similary, if {@link #setItalic} is not called, the fallback family keeps the default 701517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa * italic information. For example, calling {@code builder.setFallback("sans-serif-light")} 702517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa * is equivalent to calling {@code builder.setFallback("sans-serif").setWeight(300)} in 703f62ea8018813951e8f6a182880cadb3217e4ce37Pawin Vongmasa * terms of fallback. The default weight and italic information are overridden by calling 704f62ea8018813951e8f6a182880cadb3217e4ce37Pawin Vongmasa * {@link #setWeight} and {@link #setItalic}. For example, if a Typeface is constructed 705517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa * using {@code builder.setFallback("sans-serif-light").setWeight(700)}, the fallback text 706517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa * will render as sans serif bold. 7078ff40189817e95c7a56e347398d20e60d7534ee6Pawin Vongmasa * 7088ff40189817e95c7a56e347398d20e60d7534ee6Pawin Vongmasa * @param familyName A family name to be used for fallback if the provided font can not be 7098ff40189817e95c7a56e347398d20e60d7534ee6Pawin Vongmasa * used. By passing {@code null}, build() returns {@code null}. 7108ff40189817e95c7a56e347398d20e60d7534ee6Pawin Vongmasa * If {@link #setFallback} is not called on the builder, {@code null} 7119c47c97ecac581d66b6febafd156618247e86742Pawin Vongmasa * is assumed. 7129c47c97ecac581d66b6febafd156618247e86742Pawin Vongmasa */ 7139c47c97ecac581d66b6febafd156618247e86742Pawin Vongmasa public Builder setFallback(@Nullable String familyName) { 7149c47c97ecac581d66b6febafd156618247e86742Pawin Vongmasa mFallbackFamilyName = familyName; 7159c47c97ecac581d66b6febafd156618247e86742Pawin Vongmasa return this; 7169c47c97ecac581d66b6febafd156618247e86742Pawin Vongmasa } 7179c47c97ecac581d66b6febafd156618247e86742Pawin Vongmasa 7189c47c97ecac581d66b6febafd156618247e86742Pawin Vongmasa /** 719517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa * Creates a unique id for a given AssetManager and asset path. 720517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa * 721517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa * @param mgr AssetManager instance 722517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa * @param path The path for the asset. 723517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa * @param ttcIndex The TTC index for the font. 724517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa * @param axes The font variation settings. 725517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa * @return Unique id for a given AssetManager and asset path. 726517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa */ 727517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa private static String createAssetUid(final AssetManager mgr, String path, int ttcIndex, 728517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa @Nullable FontVariationAxis[] axes, int weight, int italic) { 729517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa final SparseArray<String> pkgs = mgr.getAssignedPackageIdentifiers(); 730517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa final StringBuilder builder = new StringBuilder(); 731517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa final int size = pkgs.size(); 732517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa for (int i = 0; i < size; i++) { 733517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa builder.append(pkgs.valueAt(i)); 734517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa builder.append("-"); 735517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa } 736517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa builder.append(path); 737517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa builder.append("-"); 738517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa builder.append(Integer.toString(ttcIndex)); 739517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa builder.append("-"); 740517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa builder.append(Integer.toString(weight)); 741517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa builder.append("-"); 742517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa builder.append(Integer.toString(italic)); 743517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa builder.append("-"); 744517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa if (axes != null) { 745517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa for (FontVariationAxis axis : axes) { 746517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa builder.append(axis.getTag()); 747517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa builder.append("-"); 748517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa builder.append(Float.toString(axis.getStyleValue())); 749517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa } 750517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa } 751517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa return builder.toString(); 752517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa } 753517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa 754517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa private static final Object sLock = new Object(); 755517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa // TODO: Unify with Typeface.sTypefaceCache. 756517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa @GuardedBy("sLock") 757517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa private static final LongSparseArray<SparseArray<Typeface>> sTypefaceCache = 758517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa new LongSparseArray<>(3); 759517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa 760517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa private Typeface resolveFallbackTypeface() { 761517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa if (mFallbackFamilyName == null) { 762517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa return null; 763517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa } 764517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa 765517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa Typeface base = sSystemFontMap.get(mFallbackFamilyName); 766517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa if (base == null) { 767517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa base = sDefaultTypeface; 768517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa } 769517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa 770517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa if (mWeight == RESOLVE_BY_FONT_TABLE && mItalic == RESOLVE_BY_FONT_TABLE) { 771517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa return base; 772517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa } 773517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa 774517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa final int weight = (mWeight == RESOLVE_BY_FONT_TABLE) ? base.mBaseWeight : mWeight; 775517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa final boolean italic = 776517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa (mItalic == RESOLVE_BY_FONT_TABLE) ? (base.mStyle & ITALIC) != 0 : mItalic == 1; 777517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa final int key = weight << 1 | (italic ? 1 : 0); 778517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa 779517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa Typeface typeface; 780517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa synchronized(sLock) { 781517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa SparseArray<Typeface> innerCache = sTypefaceCache.get(base.native_instance); 782517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa if (innerCache != null) { 783517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa typeface = innerCache.get(key); 784517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa if (typeface != null) { 785517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa return typeface; 786517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa } 787517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa } 788517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa 789517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa typeface = new Typeface( 790517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa nativeCreateFromTypefaceWithExactStyle( 791517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa base.native_instance, weight, italic)); 792517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa 793517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa if (innerCache == null) { 794517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa innerCache = new SparseArray<>(4); // [regular, bold] x [upright, italic] 795517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa sTypefaceCache.put(base.native_instance, innerCache); 796517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa } 797517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa innerCache.put(key, typeface); 798517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa } 799517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa return typeface; 800517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa } 801517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa 802517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa /** 803517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa * Generates new Typeface from specified configuration. 804517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa * 805517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa * @return Newly created Typeface. May return null if some parameters are invalid. 806517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa */ 807517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa public Typeface build() { 808517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa if (mFd != null) { // Builder is created with file descriptor. 809517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa try (FileInputStream fis = new FileInputStream(mFd)) { 810517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa FileChannel channel = fis.getChannel(); 811517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa long size = channel.size(); 812517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa ByteBuffer buffer = channel.map(FileChannel.MapMode.READ_ONLY, 0, size); 813517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa 814517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa final FontFamily fontFamily = new FontFamily(); 815517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa if (!fontFamily.addFontFromBuffer(buffer, mTtcIndex, mAxes, mWeight, mItalic)) { 816517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa fontFamily.abortCreation(); 817517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa return resolveFallbackTypeface(); 818517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa } 819517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa if (!fontFamily.freeze()) { 820517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa return resolveFallbackTypeface(); 821517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa } 822517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa FontFamily[] families = { fontFamily }; 823517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa return createFromFamiliesWithDefault(families, mWeight, mItalic); 824517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa } catch (IOException e) { 825517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa return resolveFallbackTypeface(); 826517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa } 827517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa } else if (mAssetManager != null) { // Builder is created with asset manager. 828517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa final String key = createAssetUid( 829517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa mAssetManager, mPath, mTtcIndex, mAxes, mWeight, mItalic); 830517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa synchronized (sLock) { 831517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa Typeface typeface = sDynamicTypefaceCache.get(key); 832517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa if (typeface != null) return typeface; 833517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa final FontFamily fontFamily = new FontFamily(); 834517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa if (!fontFamily.addFontFromAssetManager(mAssetManager, mPath, mTtcIndex, 835517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa true /* isAsset */, mTtcIndex, mWeight, mItalic, mAxes)) { 836517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa fontFamily.abortCreation(); 837517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa return resolveFallbackTypeface(); 838517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa } 839517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa if (!fontFamily.freeze()) { 840517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa return resolveFallbackTypeface(); 841517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa } 842517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa FontFamily[] families = { fontFamily }; 843517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa typeface = createFromFamiliesWithDefault(families, mWeight, mItalic); 844517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa sDynamicTypefaceCache.put(key, typeface); 845517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa return typeface; 846517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa } 847517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa } else if (mPath != null) { // Builder is created with file path. 848517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa final FontFamily fontFamily = new FontFamily(); 849517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa if (!fontFamily.addFont(mPath, mTtcIndex, mAxes, mWeight, mItalic)) { 850517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa fontFamily.abortCreation(); 851517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa return resolveFallbackTypeface(); 852517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa } 853517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa if (!fontFamily.freeze()) { 854517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa return resolveFallbackTypeface(); 855517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa } 856517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa FontFamily[] families = { fontFamily }; 857517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa return createFromFamiliesWithDefault(families, mWeight, mItalic); 858517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa } else if (mFonts != null) { 859517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa final FontFamily fontFamily = new FontFamily(); 860517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa boolean atLeastOneFont = false; 861517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa for (FontsContract.FontInfo font : mFonts) { 862517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa final ByteBuffer fontBuffer = mFontBuffers.get(font.getUri()); 863517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa if (fontBuffer == null) { 864517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa continue; // skip 865517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa } 866517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa final boolean success = fontFamily.addFontFromBuffer(fontBuffer, 867517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa font.getTtcIndex(), font.getAxes(), font.getWeight(), 868517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa font.isItalic() ? STYLE_ITALIC : STYLE_NORMAL); 869517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa if (!success) { 870517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa fontFamily.abortCreation(); 871517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa return null; 872517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa } 873517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa atLeastOneFont = true; 874517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa } 875517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa if (!atLeastOneFont) { 876f62ea8018813951e8f6a182880cadb3217e4ce37Pawin Vongmasa // No fonts are avaialble. No need to create new Typeface and returns fallback 877517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa // Typeface instead. 878517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa fontFamily.abortCreation(); 879517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa return null; 880517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa } 881517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa fontFamily.freeze(); 882517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa FontFamily[] families = { fontFamily }; 883517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa return createFromFamiliesWithDefault(families, mWeight, mItalic); 884517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa } 885517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa 886517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa // Must not reach here. 887517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa throw new IllegalArgumentException("No source was set."); 888517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa } 889517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa } 890517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa 891517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa /** 892eeac97b18ca5c939bf2ac59334d36d54f705af3dPawin Vongmasa * Create a typeface object given a family name, and option style information. 893517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa * If null is passed for the name, then the "default" font will be chosen. 894517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa * The resulting typeface object can be queried (getStyle()) to discover what 895517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa * its "real" style characteristics are. 896517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa * 897517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa * @param familyName May be null. The name of the font family. 898517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa * @param style The style (normal, bold, italic) of the typeface. 899517b0e090680e378f056677201426ed9dc325c65Pawin Vongmasa * e.g. NORMAL, BOLD, ITALIC, BOLD_ITALIC 900 * @return The best matching typeface. 901 */ 902 public static Typeface create(String familyName, int style) { 903 if (sSystemFontMap != null) { 904 return create(sSystemFontMap.get(familyName), style); 905 } 906 return null; 907 } 908 909 /** 910 * Create a typeface object that best matches the specified existing 911 * typeface and the specified Style. Use this call if you want to pick a new 912 * style from the same family of an existing typeface object. If family is 913 * null, this selects from the default font's family. 914 * 915 * @param family May be null. The name of the existing type face. 916 * @param style The style (normal, bold, italic) of the typeface. 917 * e.g. NORMAL, BOLD, ITALIC, BOLD_ITALIC 918 * @return The best matching typeface. 919 */ 920 public static Typeface create(Typeface family, int style) { 921 if (style < 0 || style > 3) { 922 style = 0; 923 } 924 long ni = 0; 925 if (family != null) { 926 // Return early if we're asked for the same face/style 927 if (family.mStyle == style) { 928 return family; 929 } 930 931 ni = family.native_instance; 932 } 933 934 Typeface typeface; 935 SparseArray<Typeface> styles = sTypefaceCache.get(ni); 936 937 if (styles != null) { 938 typeface = styles.get(style); 939 if (typeface != null) { 940 return typeface; 941 } 942 } 943 944 typeface = new Typeface(nativeCreateFromTypeface(ni, style)); 945 if (styles == null) { 946 styles = new SparseArray<Typeface>(4); 947 sTypefaceCache.put(ni, styles); 948 } 949 styles.put(style, typeface); 950 951 return typeface; 952 } 953 954 /** @hide */ 955 public static Typeface createFromTypefaceWithVariation(Typeface family, 956 List<FontVariationAxis> axes) { 957 final long ni = family == null ? 0 : family.native_instance; 958 return new Typeface(nativeCreateFromTypefaceWithVariation(ni, axes)); 959 } 960 961 /** 962 * Returns one of the default typeface objects, based on the specified style 963 * 964 * @return the default typeface that corresponds to the style 965 */ 966 public static Typeface defaultFromStyle(int style) { 967 return sDefaults[style]; 968 } 969 970 /** 971 * Create a new typeface from the specified font data. 972 * 973 * @param mgr The application's asset manager 974 * @param path The file name of the font data in the assets directory 975 * @return The new typeface. 976 */ 977 public static Typeface createFromAsset(AssetManager mgr, String path) { 978 if (path == null) { 979 throw new NullPointerException(); // for backward compatibility 980 } 981 if (sFallbackFonts != null) { 982 synchronized (sLock) { 983 Typeface typeface = new Builder(mgr, path).build(); 984 if (typeface != null) return typeface; 985 986 final String key = Builder.createAssetUid(mgr, path, 0 /* ttcIndex */, 987 null /* axes */, RESOLVE_BY_FONT_TABLE, RESOLVE_BY_FONT_TABLE); 988 typeface = sDynamicTypefaceCache.get(key); 989 if (typeface != null) return typeface; 990 991 final FontFamily fontFamily = new FontFamily(); 992 if (fontFamily.addFontFromAssetManager(mgr, path, 0, true /* isAsset */, 993 0 /* ttc index */, RESOLVE_BY_FONT_TABLE, RESOLVE_BY_FONT_TABLE, 994 null /* axes */)) { 995 // Due to backward compatibility, even if the font is not supported by our font 996 // stack, we need to place the empty font at the first place. The typeface with 997 // empty font behaves different from default typeface especially in fallback 998 // font selection. 999 fontFamily.allowUnsupportedFont(); 1000 fontFamily.freeze(); 1001 final FontFamily[] families = { fontFamily }; 1002 typeface = createFromFamiliesWithDefault(families, RESOLVE_BY_FONT_TABLE, 1003 RESOLVE_BY_FONT_TABLE); 1004 sDynamicTypefaceCache.put(key, typeface); 1005 return typeface; 1006 } else { 1007 fontFamily.abortCreation(); 1008 } 1009 } 1010 } 1011 throw new RuntimeException("Font asset not found " + path); 1012 } 1013 1014 /** 1015 * Creates a unique id for a given font provider and query. 1016 */ 1017 private static String createProviderUid(String authority, String query) { 1018 final StringBuilder builder = new StringBuilder(); 1019 builder.append("provider:"); 1020 builder.append(authority); 1021 builder.append("-"); 1022 builder.append(query); 1023 return builder.toString(); 1024 } 1025 1026 /** 1027 * Create a new typeface from the specified font file. 1028 * 1029 * @param path The path to the font data. 1030 * @return The new typeface. 1031 */ 1032 public static Typeface createFromFile(@Nullable File path) { 1033 // For the compatibility reasons, leaving possible NPE here. 1034 // See android.graphics.cts.TypefaceTest#testCreateFromFileByFileReferenceNull 1035 return createFromFile(path.getAbsolutePath()); 1036 } 1037 1038 /** 1039 * Create a new typeface from the specified font file. 1040 * 1041 * @param path The full path to the font data. 1042 * @return The new typeface. 1043 */ 1044 public static Typeface createFromFile(@Nullable String path) { 1045 if (sFallbackFonts != null) { 1046 final FontFamily fontFamily = new FontFamily(); 1047 if (fontFamily.addFont(path, 0 /* ttcIndex */, null /* axes */, 1048 RESOLVE_BY_FONT_TABLE, RESOLVE_BY_FONT_TABLE)) { 1049 // Due to backward compatibility, even if the font is not supported by our font 1050 // stack, we need to place the empty font at the first place. The typeface with 1051 // empty font behaves different from default typeface especially in fallback font 1052 // selection. 1053 fontFamily.allowUnsupportedFont(); 1054 fontFamily.freeze(); 1055 FontFamily[] families = { fontFamily }; 1056 return createFromFamiliesWithDefault(families, RESOLVE_BY_FONT_TABLE, 1057 RESOLVE_BY_FONT_TABLE); 1058 } else { 1059 fontFamily.abortCreation(); 1060 } 1061 } 1062 throw new RuntimeException("Font not found " + path); 1063 } 1064 1065 /** 1066 * Create a new typeface from an array of font families. 1067 * 1068 * @param families array of font families 1069 */ 1070 private static Typeface createFromFamilies(FontFamily[] families) { 1071 long[] ptrArray = new long[families.length]; 1072 for (int i = 0; i < families.length; i++) { 1073 ptrArray[i] = families[i].mNativePtr; 1074 } 1075 return new Typeface(nativeCreateFromArray( 1076 ptrArray, RESOLVE_BY_FONT_TABLE, RESOLVE_BY_FONT_TABLE)); 1077 } 1078 1079 /** 1080 * Create a new typeface from an array of font families, including 1081 * also the font families in the fallback list. 1082 * @param weight the weight for this family. {@link RESOLVE_BY_FONT_TABLE} can be used. In that 1083 * case, the table information in the first family's font is used. If the first 1084 * family has multiple fonts, the closest to the regular weight and upright font 1085 * is used. 1086 * @param italic the italic information for this family. {@link RESOLVE_BY_FONT_TABLE} can be 1087 * used. In that case, the table information in the first family's font is used. 1088 * If the first family has multiple fonts, the closest to the regular weight and 1089 * upright font is used. 1090 * @param families array of font families 1091 */ 1092 private static Typeface createFromFamiliesWithDefault(FontFamily[] families, 1093 int weight, int italic) { 1094 long[] ptrArray = new long[families.length + sFallbackFonts.length]; 1095 for (int i = 0; i < families.length; i++) { 1096 ptrArray[i] = families[i].mNativePtr; 1097 } 1098 for (int i = 0; i < sFallbackFonts.length; i++) { 1099 ptrArray[i + families.length] = sFallbackFonts[i].mNativePtr; 1100 } 1101 return new Typeface(nativeCreateFromArray(ptrArray, weight, italic)); 1102 } 1103 1104 // don't allow clients to call this directly 1105 private Typeface(long ni) { 1106 if (ni == 0) { 1107 throw new RuntimeException("native typeface cannot be made"); 1108 } 1109 1110 native_instance = ni; 1111 mStyle = nativeGetStyle(ni); 1112 mBaseWeight = nativeGetBaseWeight(ni); 1113 } 1114 1115 private static FontFamily makeFamilyFromParsed(FontConfig.Family family, 1116 Map<String, ByteBuffer> bufferForPath) { 1117 FontFamily fontFamily = new FontFamily(family.getLanguage(), family.getVariant()); 1118 for (FontConfig.Font font : family.getFonts()) { 1119 String fullPathName = "/system/fonts/" + font.getFontName(); 1120 ByteBuffer fontBuffer = bufferForPath.get(fullPathName); 1121 if (fontBuffer == null) { 1122 try (FileInputStream file = new FileInputStream(fullPathName)) { 1123 FileChannel fileChannel = file.getChannel(); 1124 long fontSize = fileChannel.size(); 1125 fontBuffer = fileChannel.map(FileChannel.MapMode.READ_ONLY, 0, fontSize); 1126 bufferForPath.put(fullPathName, fontBuffer); 1127 } catch (IOException e) { 1128 Log.e(TAG, "Error mapping font file " + fullPathName); 1129 continue; 1130 } 1131 } 1132 if (!fontFamily.addFontFromBuffer(fontBuffer, font.getTtcIndex(), font.getAxes(), 1133 font.getWeight(), font.isItalic() ? STYLE_ITALIC : STYLE_NORMAL)) { 1134 Log.e(TAG, "Error creating font " + fullPathName + "#" + font.getTtcIndex()); 1135 } 1136 } 1137 if (!fontFamily.freeze()) { 1138 // Treat as system error since reaching here means that a system pre-installed font 1139 // can't be used by our font stack. 1140 Log.e(TAG, "Unable to load Family: " + family.getName() + ":" + family.getLanguage()); 1141 } 1142 return fontFamily; 1143 } 1144 1145 /* 1146 * (non-Javadoc) 1147 * 1148 * This should only be called once, from the static class initializer block. 1149 */ 1150 private static void init() { 1151 // Load font config and initialize Minikin state 1152 File systemFontConfigLocation = getSystemFontConfigLocation(); 1153 File configFilename = new File(systemFontConfigLocation, FONTS_CONFIG); 1154 try { 1155 FileInputStream fontsIn = new FileInputStream(configFilename); 1156 FontConfig fontConfig = FontListParser.parse(fontsIn); 1157 1158 Map<String, ByteBuffer> bufferForPath = new HashMap<String, ByteBuffer>(); 1159 1160 List<FontFamily> familyList = new ArrayList<FontFamily>(); 1161 // Note that the default typeface is always present in the fallback list; 1162 // this is an enhancement from pre-Minikin behavior. 1163 for (int i = 0; i < fontConfig.getFamilies().length; i++) { 1164 FontConfig.Family f = fontConfig.getFamilies()[i]; 1165 if (i == 0 || f.getName() == null) { 1166 familyList.add(makeFamilyFromParsed(f, bufferForPath)); 1167 } 1168 } 1169 sFallbackFonts = familyList.toArray(new FontFamily[familyList.size()]); 1170 setDefault(Typeface.createFromFamilies(sFallbackFonts)); 1171 1172 Map<String, Typeface> systemFonts = new HashMap<String, Typeface>(); 1173 for (int i = 0; i < fontConfig.getFamilies().length; i++) { 1174 Typeface typeface; 1175 FontConfig.Family f = fontConfig.getFamilies()[i]; 1176 if (f.getName() != null) { 1177 if (i == 0) { 1178 // The first entry is the default typeface; no sense in 1179 // duplicating the corresponding FontFamily. 1180 typeface = sDefaultTypeface; 1181 } else { 1182 FontFamily fontFamily = makeFamilyFromParsed(f, bufferForPath); 1183 FontFamily[] families = { fontFamily }; 1184 typeface = Typeface.createFromFamiliesWithDefault(families, 1185 RESOLVE_BY_FONT_TABLE, RESOLVE_BY_FONT_TABLE); 1186 } 1187 systemFonts.put(f.getName(), typeface); 1188 } 1189 } 1190 for (FontConfig.Alias alias : fontConfig.getAliases()) { 1191 Typeface base = systemFonts.get(alias.getToName()); 1192 Typeface newFace = base; 1193 int weight = alias.getWeight(); 1194 if (weight != 400) { 1195 newFace = new Typeface(nativeCreateWeightAlias(base.native_instance, weight)); 1196 } 1197 systemFonts.put(alias.getName(), newFace); 1198 } 1199 sSystemFontMap = systemFonts; 1200 1201 } catch (RuntimeException e) { 1202 Log.w(TAG, "Didn't create default family (most likely, non-Minikin build)", e); 1203 // TODO: normal in non-Minikin case, remove or make error when Minikin-only 1204 } catch (FileNotFoundException e) { 1205 Log.e(TAG, "Error opening " + configFilename, e); 1206 } catch (IOException e) { 1207 Log.e(TAG, "Error reading " + configFilename, e); 1208 } catch (XmlPullParserException e) { 1209 Log.e(TAG, "XML parse exception for " + configFilename, e); 1210 } 1211 } 1212 1213 static { 1214 init(); 1215 // Set up defaults and typefaces exposed in public API 1216 DEFAULT = create((String) null, 0); 1217 DEFAULT_BOLD = create((String) null, Typeface.BOLD); 1218 SANS_SERIF = create("sans-serif", 0); 1219 SERIF = create("serif", 0); 1220 MONOSPACE = create("monospace", 0); 1221 1222 sDefaults = new Typeface[] { 1223 DEFAULT, 1224 DEFAULT_BOLD, 1225 create((String) null, Typeface.ITALIC), 1226 create((String) null, Typeface.BOLD_ITALIC), 1227 }; 1228 1229 } 1230 1231 private static File getSystemFontConfigLocation() { 1232 return new File("/system/etc/"); 1233 } 1234 1235 @Override 1236 protected void finalize() throws Throwable { 1237 try { 1238 nativeUnref(native_instance); 1239 native_instance = 0; // Other finalizers can still call us. 1240 } finally { 1241 super.finalize(); 1242 } 1243 } 1244 1245 @Override 1246 public boolean equals(Object o) { 1247 if (this == o) return true; 1248 if (o == null || getClass() != o.getClass()) return false; 1249 1250 Typeface typeface = (Typeface) o; 1251 1252 return mStyle == typeface.mStyle && native_instance == typeface.native_instance; 1253 } 1254 1255 @Override 1256 public int hashCode() { 1257 /* 1258 * Modified method for hashCode with long native_instance derived from 1259 * http://developer.android.com/reference/java/lang/Object.html 1260 */ 1261 int result = 17; 1262 result = 31 * result + (int) (native_instance ^ (native_instance >>> 32)); 1263 result = 31 * result + mStyle; 1264 return result; 1265 } 1266 1267 /** @hide */ 1268 public boolean isSupportedAxes(int axis) { 1269 if (mSupportedAxes == null) { 1270 synchronized (this) { 1271 if (mSupportedAxes == null) { 1272 mSupportedAxes = nativeGetSupportedAxes(native_instance); 1273 if (mSupportedAxes == null) { 1274 mSupportedAxes = EMPTY_AXES; 1275 } 1276 } 1277 } 1278 } 1279 return Arrays.binarySearch(mSupportedAxes, axis) > 0; 1280 } 1281 1282 private static native long nativeCreateFromTypeface(long native_instance, int style); 1283 private static native long nativeCreateFromTypefaceWithExactStyle( 1284 long native_instance, int weight, boolean italic); 1285 // TODO: clean up: change List<FontVariationAxis> to FontVariationAxis[] 1286 private static native long nativeCreateFromTypefaceWithVariation( 1287 long native_instance, List<FontVariationAxis> axes); 1288 private static native long nativeCreateWeightAlias(long native_instance, int weight); 1289 private static native void nativeUnref(long native_instance); 1290 private static native int nativeGetStyle(long native_instance); 1291 private static native int nativeGetBaseWeight(long native_instance); 1292 private static native long nativeCreateFromArray(long[] familyArray, int weight, int italic); 1293 private static native void nativeSetDefault(long native_instance); 1294 private static native int[] nativeGetSupportedAxes(long native_instance); 1295} 1296