1baef8c1ffe5c900fb0da9512654bf249b5fc9269Deepanshu Gupta/* 2baef8c1ffe5c900fb0da9512654bf249b5fc9269Deepanshu Gupta * Copyright (C) 2014 The Android Open Source Project 3baef8c1ffe5c900fb0da9512654bf249b5fc9269Deepanshu Gupta * 4baef8c1ffe5c900fb0da9512654bf249b5fc9269Deepanshu Gupta * Licensed under the Apache License, Version 2.0 (the "License"); 5baef8c1ffe5c900fb0da9512654bf249b5fc9269Deepanshu Gupta * you may not use this file except in compliance with the License. 6baef8c1ffe5c900fb0da9512654bf249b5fc9269Deepanshu Gupta * You may obtain a copy of the License at 7baef8c1ffe5c900fb0da9512654bf249b5fc9269Deepanshu Gupta * 8baef8c1ffe5c900fb0da9512654bf249b5fc9269Deepanshu Gupta * http://www.apache.org/licenses/LICENSE-2.0 9baef8c1ffe5c900fb0da9512654bf249b5fc9269Deepanshu Gupta * 10baef8c1ffe5c900fb0da9512654bf249b5fc9269Deepanshu Gupta * Unless required by applicable law or agreed to in writing, software 11baef8c1ffe5c900fb0da9512654bf249b5fc9269Deepanshu Gupta * distributed under the License is distributed on an "AS IS" BASIS, 12baef8c1ffe5c900fb0da9512654bf249b5fc9269Deepanshu Gupta * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13baef8c1ffe5c900fb0da9512654bf249b5fc9269Deepanshu Gupta * See the License for the specific language governing permissions and 14baef8c1ffe5c900fb0da9512654bf249b5fc9269Deepanshu Gupta * limitations under the License. 15baef8c1ffe5c900fb0da9512654bf249b5fc9269Deepanshu Gupta */ 16baef8c1ffe5c900fb0da9512654bf249b5fc9269Deepanshu Gupta 17baef8c1ffe5c900fb0da9512654bf249b5fc9269Deepanshu Guptapackage android.graphics; 18baef8c1ffe5c900fb0da9512654bf249b5fc9269Deepanshu Gupta 19d51834bdfad0cd3142ac464ab3a3b0db14f884c3Deepanshu Guptaimport com.android.ide.common.rendering.api.AssetRepository; 20baef8c1ffe5c900fb0da9512654bf249b5fc9269Deepanshu Guptaimport com.android.ide.common.rendering.api.LayoutLog; 21baef8c1ffe5c900fb0da9512654bf249b5fc9269Deepanshu Guptaimport com.android.layoutlib.bridge.Bridge; 22baef8c1ffe5c900fb0da9512654bf249b5fc9269Deepanshu Guptaimport com.android.layoutlib.bridge.impl.DelegateManager; 23baef8c1ffe5c900fb0da9512654bf249b5fc9269Deepanshu Guptaimport com.android.tools.layoutlib.annotations.LayoutlibDelegate; 24baef8c1ffe5c900fb0da9512654bf249b5fc9269Deepanshu Gupta 25476e582d2ffdf25102d4c55f8c242baa3d21d37fDeepanshu Guptaimport android.annotation.NonNull; 26476e582d2ffdf25102d4c55f8c242baa3d21d37fDeepanshu Guptaimport android.annotation.Nullable; 27ad69aee5ed503d9592c10a0f6d1a5b617d99e6c5Deepanshu Guptaimport android.content.res.AssetManager; 28d51834bdfad0cd3142ac464ab3a3b0db14f884c3Deepanshu Guptaimport android.content.res.BridgeAssetManager; 29ad69aee5ed503d9592c10a0f6d1a5b617d99e6c5Deepanshu Gupta 30baef8c1ffe5c900fb0da9512654bf249b5fc9269Deepanshu Guptaimport java.awt.Font; 31b0d767dcf17dd393646b8fc3e8c9f46dfe12e230Deepanshu Guptaimport java.awt.FontFormatException; 32baef8c1ffe5c900fb0da9512654bf249b5fc9269Deepanshu Guptaimport java.io.File; 330e4be2540984235a0a7b84ea0466ef3c92d27b07Deepanshu Guptaimport java.io.FileNotFoundException; 34d51834bdfad0cd3142ac464ab3a3b0db14f884c3Deepanshu Guptaimport java.io.IOException; 35d51834bdfad0cd3142ac464ab3a3b0db14f884c3Deepanshu Guptaimport java.io.InputStream; 36baef8c1ffe5c900fb0da9512654bf249b5fc9269Deepanshu Guptaimport java.util.ArrayList; 37e644ff8d92ba040d11636be0fb6c433b52bcc6c2Deepanshu Guptaimport java.util.Collections; 38e644ff8d92ba040d11636be0fb6c433b52bcc6c2Deepanshu Guptaimport java.util.HashSet; 39d51834bdfad0cd3142ac464ab3a3b0db14f884c3Deepanshu Guptaimport java.util.LinkedHashMap; 40baef8c1ffe5c900fb0da9512654bf249b5fc9269Deepanshu Guptaimport java.util.List; 41d51834bdfad0cd3142ac464ab3a3b0db14f884c3Deepanshu Guptaimport java.util.Map; 42d51834bdfad0cd3142ac464ab3a3b0db14f884c3Deepanshu Guptaimport java.util.Map.Entry; 430e4be2540984235a0a7b84ea0466ef3c92d27b07Deepanshu Guptaimport java.util.Scanner; 44e644ff8d92ba040d11636be0fb6c433b52bcc6c2Deepanshu Guptaimport java.util.Set; 45baef8c1ffe5c900fb0da9512654bf249b5fc9269Deepanshu Gupta 46baef8c1ffe5c900fb0da9512654bf249b5fc9269Deepanshu Guptaimport static android.graphics.Typeface_Delegate.SYSTEM_FONTS; 47baef8c1ffe5c900fb0da9512654bf249b5fc9269Deepanshu Gupta 48baef8c1ffe5c900fb0da9512654bf249b5fc9269Deepanshu Gupta/** 49baef8c1ffe5c900fb0da9512654bf249b5fc9269Deepanshu Gupta * Delegate implementing the native methods of android.graphics.FontFamily 50baef8c1ffe5c900fb0da9512654bf249b5fc9269Deepanshu Gupta * 51baef8c1ffe5c900fb0da9512654bf249b5fc9269Deepanshu Gupta * Through the layoutlib_create tool, the original native methods of FontFamily have been replaced 52baef8c1ffe5c900fb0da9512654bf249b5fc9269Deepanshu Gupta * by calls to methods of the same name in this delegate class. 53baef8c1ffe5c900fb0da9512654bf249b5fc9269Deepanshu Gupta * 54baef8c1ffe5c900fb0da9512654bf249b5fc9269Deepanshu Gupta * This class behaves like the original native implementation, but in Java, keeping previously 55baef8c1ffe5c900fb0da9512654bf249b5fc9269Deepanshu Gupta * native data into its own objects and mapping them to int that are sent back and forth between 56baef8c1ffe5c900fb0da9512654bf249b5fc9269Deepanshu Gupta * it and the original FontFamily class. 57baef8c1ffe5c900fb0da9512654bf249b5fc9269Deepanshu Gupta * 58baef8c1ffe5c900fb0da9512654bf249b5fc9269Deepanshu Gupta * @see DelegateManager 59baef8c1ffe5c900fb0da9512654bf249b5fc9269Deepanshu Gupta */ 60baef8c1ffe5c900fb0da9512654bf249b5fc9269Deepanshu Guptapublic class FontFamily_Delegate { 61baef8c1ffe5c900fb0da9512654bf249b5fc9269Deepanshu Gupta 62145bc2d067faa3fb49b71e9e8c8c70b40564061aDeepanshu Gupta public static final int DEFAULT_FONT_WEIGHT = 400; 63145bc2d067faa3fb49b71e9e8c8c70b40564061aDeepanshu Gupta public static final int BOLD_FONT_WEIGHT_DELTA = 300; 64145bc2d067faa3fb49b71e9e8c8c70b40564061aDeepanshu Gupta public static final int BOLD_FONT_WEIGHT = 700; 65145bc2d067faa3fb49b71e9e8c8c70b40564061aDeepanshu Gupta 66baef8c1ffe5c900fb0da9512654bf249b5fc9269Deepanshu Gupta private static final String FONT_SUFFIX_ITALIC = "Italic.ttf"; 670e4be2540984235a0a7b84ea0466ef3c92d27b07Deepanshu Gupta private static final String FN_ALL_FONTS_LIST = "fontsInSdk.txt"; 68d51834bdfad0cd3142ac464ab3a3b0db14f884c3Deepanshu Gupta private static final String EXTENSION_OTF = ".otf"; 69d51834bdfad0cd3142ac464ab3a3b0db14f884c3Deepanshu Gupta 70d51834bdfad0cd3142ac464ab3a3b0db14f884c3Deepanshu Gupta private static final int CACHE_SIZE = 10; 71d51834bdfad0cd3142ac464ab3a3b0db14f884c3Deepanshu Gupta // The cache has a drawback that if the font file changed after the font object was created, 72d51834bdfad0cd3142ac464ab3a3b0db14f884c3Deepanshu Gupta // we will not update it. 73d51834bdfad0cd3142ac464ab3a3b0db14f884c3Deepanshu Gupta private static final Map<String, FontInfo> sCache = 74d51834bdfad0cd3142ac464ab3a3b0db14f884c3Deepanshu Gupta new LinkedHashMap<String, FontInfo>(CACHE_SIZE) { 75d51834bdfad0cd3142ac464ab3a3b0db14f884c3Deepanshu Gupta @Override 76d51834bdfad0cd3142ac464ab3a3b0db14f884c3Deepanshu Gupta protected boolean removeEldestEntry(Entry<String, FontInfo> eldest) { 77d51834bdfad0cd3142ac464ab3a3b0db14f884c3Deepanshu Gupta return size() > CACHE_SIZE; 78d51834bdfad0cd3142ac464ab3a3b0db14f884c3Deepanshu Gupta } 79d51834bdfad0cd3142ac464ab3a3b0db14f884c3Deepanshu Gupta 80d51834bdfad0cd3142ac464ab3a3b0db14f884c3Deepanshu Gupta @Override 81d51834bdfad0cd3142ac464ab3a3b0db14f884c3Deepanshu Gupta public FontInfo put(String key, FontInfo value) { 82d51834bdfad0cd3142ac464ab3a3b0db14f884c3Deepanshu Gupta // renew this entry. 83d51834bdfad0cd3142ac464ab3a3b0db14f884c3Deepanshu Gupta FontInfo removed = remove(key); 84d51834bdfad0cd3142ac464ab3a3b0db14f884c3Deepanshu Gupta super.put(key, value); 85d51834bdfad0cd3142ac464ab3a3b0db14f884c3Deepanshu Gupta return removed; 86d51834bdfad0cd3142ac464ab3a3b0db14f884c3Deepanshu Gupta } 87d51834bdfad0cd3142ac464ab3a3b0db14f884c3Deepanshu Gupta }; 88e644ff8d92ba040d11636be0fb6c433b52bcc6c2Deepanshu Gupta 89baef8c1ffe5c900fb0da9512654bf249b5fc9269Deepanshu Gupta /** 90baef8c1ffe5c900fb0da9512654bf249b5fc9269Deepanshu Gupta * A class associating {@link Font} with its metadata. 91baef8c1ffe5c900fb0da9512654bf249b5fc9269Deepanshu Gupta */ 92baef8c1ffe5c900fb0da9512654bf249b5fc9269Deepanshu Gupta private static final class FontInfo { 93145bc2d067faa3fb49b71e9e8c8c70b40564061aDeepanshu Gupta @Nullable 94baef8c1ffe5c900fb0da9512654bf249b5fc9269Deepanshu Gupta Font mFont; 95145bc2d067faa3fb49b71e9e8c8c70b40564061aDeepanshu Gupta int mWeight; 96145bc2d067faa3fb49b71e9e8c8c70b40564061aDeepanshu Gupta boolean mIsItalic; 97baef8c1ffe5c900fb0da9512654bf249b5fc9269Deepanshu Gupta } 98baef8c1ffe5c900fb0da9512654bf249b5fc9269Deepanshu Gupta 99baef8c1ffe5c900fb0da9512654bf249b5fc9269Deepanshu Gupta // ---- delegate manager ---- 100baef8c1ffe5c900fb0da9512654bf249b5fc9269Deepanshu Gupta private static final DelegateManager<FontFamily_Delegate> sManager = 101baef8c1ffe5c900fb0da9512654bf249b5fc9269Deepanshu Gupta new DelegateManager<FontFamily_Delegate>(FontFamily_Delegate.class); 102baef8c1ffe5c900fb0da9512654bf249b5fc9269Deepanshu Gupta 103baef8c1ffe5c900fb0da9512654bf249b5fc9269Deepanshu Gupta // ---- delegate helper data ---- 104baef8c1ffe5c900fb0da9512654bf249b5fc9269Deepanshu Gupta private static String sFontLocation; 105baef8c1ffe5c900fb0da9512654bf249b5fc9269Deepanshu Gupta private static final List<FontFamily_Delegate> sPostInitDelegate = new 106baef8c1ffe5c900fb0da9512654bf249b5fc9269Deepanshu Gupta ArrayList<FontFamily_Delegate>(); 1070e4be2540984235a0a7b84ea0466ef3c92d27b07Deepanshu Gupta private static Set<String> SDK_FONTS; 108baef8c1ffe5c900fb0da9512654bf249b5fc9269Deepanshu Gupta 109baef8c1ffe5c900fb0da9512654bf249b5fc9269Deepanshu Gupta 110baef8c1ffe5c900fb0da9512654bf249b5fc9269Deepanshu Gupta // ---- delegate data ---- 111baef8c1ffe5c900fb0da9512654bf249b5fc9269Deepanshu Gupta private List<FontInfo> mFonts = new ArrayList<FontInfo>(); 112145bc2d067faa3fb49b71e9e8c8c70b40564061aDeepanshu Gupta 113ad69aee5ed503d9592c10a0f6d1a5b617d99e6c5Deepanshu Gupta /** 114ad69aee5ed503d9592c10a0f6d1a5b617d99e6c5Deepanshu Gupta * The variant of the Font Family - compact or elegant. 115145bc2d067faa3fb49b71e9e8c8c70b40564061aDeepanshu Gupta * <p/> 116ad69aee5ed503d9592c10a0f6d1a5b617d99e6c5Deepanshu Gupta * 0 is unspecified, 1 is compact and 2 is elegant. This needs to be kept in sync with values in 117ad69aee5ed503d9592c10a0f6d1a5b617d99e6c5Deepanshu Gupta * android.graphics.FontFamily 118ad69aee5ed503d9592c10a0f6d1a5b617d99e6c5Deepanshu Gupta * 119ad69aee5ed503d9592c10a0f6d1a5b617d99e6c5Deepanshu Gupta * @see Paint#setElegantTextHeight(boolean) 120ad69aee5ed503d9592c10a0f6d1a5b617d99e6c5Deepanshu Gupta */ 121ad69aee5ed503d9592c10a0f6d1a5b617d99e6c5Deepanshu Gupta private FontVariant mVariant; 122145bc2d067faa3fb49b71e9e8c8c70b40564061aDeepanshu Gupta // List of runnables to process fonts after sFontLoader is initialized. 123145bc2d067faa3fb49b71e9e8c8c70b40564061aDeepanshu Gupta private List<Runnable> mPostInitRunnables = new ArrayList<Runnable>(); 124e644ff8d92ba040d11636be0fb6c433b52bcc6c2Deepanshu Gupta /** @see #isValid() */ 125e644ff8d92ba040d11636be0fb6c433b52bcc6c2Deepanshu Gupta private boolean mValid = false; 126baef8c1ffe5c900fb0da9512654bf249b5fc9269Deepanshu Gupta 127baef8c1ffe5c900fb0da9512654bf249b5fc9269Deepanshu Gupta 1283c937cf5c730519e750cdee4d5fa61e2a593e33aDeepanshu Gupta // ---- Public helper class ---- 1293c937cf5c730519e750cdee4d5fa61e2a593e33aDeepanshu Gupta 1303c937cf5c730519e750cdee4d5fa61e2a593e33aDeepanshu Gupta public enum FontVariant { 1313c937cf5c730519e750cdee4d5fa61e2a593e33aDeepanshu Gupta // The order needs to be kept in sync with android.graphics.FontFamily. 1323c937cf5c730519e750cdee4d5fa61e2a593e33aDeepanshu Gupta NONE, COMPACT, ELEGANT 1333c937cf5c730519e750cdee4d5fa61e2a593e33aDeepanshu Gupta } 1343c937cf5c730519e750cdee4d5fa61e2a593e33aDeepanshu Gupta 135baef8c1ffe5c900fb0da9512654bf249b5fc9269Deepanshu Gupta // ---- Public Helper methods ---- 136baef8c1ffe5c900fb0da9512654bf249b5fc9269Deepanshu Gupta 137baef8c1ffe5c900fb0da9512654bf249b5fc9269Deepanshu Gupta public static FontFamily_Delegate getDelegate(long nativeFontFamily) { 138baef8c1ffe5c900fb0da9512654bf249b5fc9269Deepanshu Gupta return sManager.getDelegate(nativeFontFamily); 139baef8c1ffe5c900fb0da9512654bf249b5fc9269Deepanshu Gupta } 140baef8c1ffe5c900fb0da9512654bf249b5fc9269Deepanshu Gupta 141baef8c1ffe5c900fb0da9512654bf249b5fc9269Deepanshu Gupta public static synchronized void setFontLocation(String fontLocation) { 142baef8c1ffe5c900fb0da9512654bf249b5fc9269Deepanshu Gupta sFontLocation = fontLocation; 1430e4be2540984235a0a7b84ea0466ef3c92d27b07Deepanshu Gupta // init list of bundled fonts. 1440e4be2540984235a0a7b84ea0466ef3c92d27b07Deepanshu Gupta File allFonts = new File(fontLocation, FN_ALL_FONTS_LIST); 1450e4be2540984235a0a7b84ea0466ef3c92d27b07Deepanshu Gupta // Current number of fonts is 103. Use the next round number to leave scope for more fonts 1460e4be2540984235a0a7b84ea0466ef3c92d27b07Deepanshu Gupta // in the future. 1470e4be2540984235a0a7b84ea0466ef3c92d27b07Deepanshu Gupta Set<String> allFontsList = new HashSet<String>(128); 1480e4be2540984235a0a7b84ea0466ef3c92d27b07Deepanshu Gupta Scanner scanner = null; 1490e4be2540984235a0a7b84ea0466ef3c92d27b07Deepanshu Gupta try { 1500e4be2540984235a0a7b84ea0466ef3c92d27b07Deepanshu Gupta scanner = new Scanner(allFonts); 1510e4be2540984235a0a7b84ea0466ef3c92d27b07Deepanshu Gupta while (scanner.hasNext()) { 1520e4be2540984235a0a7b84ea0466ef3c92d27b07Deepanshu Gupta String name = scanner.next(); 1530e4be2540984235a0a7b84ea0466ef3c92d27b07Deepanshu Gupta // Skip font configuration files. 1540e4be2540984235a0a7b84ea0466ef3c92d27b07Deepanshu Gupta if (!name.endsWith(".xml")) { 1550e4be2540984235a0a7b84ea0466ef3c92d27b07Deepanshu Gupta allFontsList.add(name); 1560e4be2540984235a0a7b84ea0466ef3c92d27b07Deepanshu Gupta } 1570e4be2540984235a0a7b84ea0466ef3c92d27b07Deepanshu Gupta } 1580e4be2540984235a0a7b84ea0466ef3c92d27b07Deepanshu Gupta } catch (FileNotFoundException e) { 1590e4be2540984235a0a7b84ea0466ef3c92d27b07Deepanshu Gupta Bridge.getLog().error(LayoutLog.TAG_BROKEN, 1600e4be2540984235a0a7b84ea0466ef3c92d27b07Deepanshu Gupta "Unable to load the list of fonts. Try re-installing the SDK Platform from the SDK Manager.", 1610e4be2540984235a0a7b84ea0466ef3c92d27b07Deepanshu Gupta e, null); 1620e4be2540984235a0a7b84ea0466ef3c92d27b07Deepanshu Gupta } finally { 1630e4be2540984235a0a7b84ea0466ef3c92d27b07Deepanshu Gupta if (scanner != null) { 1640e4be2540984235a0a7b84ea0466ef3c92d27b07Deepanshu Gupta scanner.close(); 1650e4be2540984235a0a7b84ea0466ef3c92d27b07Deepanshu Gupta } 1660e4be2540984235a0a7b84ea0466ef3c92d27b07Deepanshu Gupta } 1670e4be2540984235a0a7b84ea0466ef3c92d27b07Deepanshu Gupta SDK_FONTS = Collections.unmodifiableSet(allFontsList); 168baef8c1ffe5c900fb0da9512654bf249b5fc9269Deepanshu Gupta for (FontFamily_Delegate fontFamily : sPostInitDelegate) { 169baef8c1ffe5c900fb0da9512654bf249b5fc9269Deepanshu Gupta fontFamily.init(); 170baef8c1ffe5c900fb0da9512654bf249b5fc9269Deepanshu Gupta } 171baef8c1ffe5c900fb0da9512654bf249b5fc9269Deepanshu Gupta sPostInitDelegate.clear(); 172baef8c1ffe5c900fb0da9512654bf249b5fc9269Deepanshu Gupta } 173baef8c1ffe5c900fb0da9512654bf249b5fc9269Deepanshu Gupta 174145bc2d067faa3fb49b71e9e8c8c70b40564061aDeepanshu Gupta @Nullable 175145bc2d067faa3fb49b71e9e8c8c70b40564061aDeepanshu Gupta public Font getFont(int desiredWeight, boolean isItalic) { 176145bc2d067faa3fb49b71e9e8c8c70b40564061aDeepanshu Gupta FontInfo desiredStyle = new FontInfo(); 177145bc2d067faa3fb49b71e9e8c8c70b40564061aDeepanshu Gupta desiredStyle.mWeight = desiredWeight; 178145bc2d067faa3fb49b71e9e8c8c70b40564061aDeepanshu Gupta desiredStyle.mIsItalic = isItalic; 179145bc2d067faa3fb49b71e9e8c8c70b40564061aDeepanshu Gupta FontInfo bestFont = null; 180145bc2d067faa3fb49b71e9e8c8c70b40564061aDeepanshu Gupta int bestMatch = Integer.MAX_VALUE; 181baef8c1ffe5c900fb0da9512654bf249b5fc9269Deepanshu Gupta for (FontInfo font : mFonts) { 182145bc2d067faa3fb49b71e9e8c8c70b40564061aDeepanshu Gupta int match = computeMatch(font, desiredStyle); 183145bc2d067faa3fb49b71e9e8c8c70b40564061aDeepanshu Gupta if (match < bestMatch) { 184145bc2d067faa3fb49b71e9e8c8c70b40564061aDeepanshu Gupta bestMatch = match; 185145bc2d067faa3fb49b71e9e8c8c70b40564061aDeepanshu Gupta bestFont = font; 186baef8c1ffe5c900fb0da9512654bf249b5fc9269Deepanshu Gupta } 187baef8c1ffe5c900fb0da9512654bf249b5fc9269Deepanshu Gupta } 188145bc2d067faa3fb49b71e9e8c8c70b40564061aDeepanshu Gupta if (bestFont == null) { 189145bc2d067faa3fb49b71e9e8c8c70b40564061aDeepanshu Gupta return null; 190baef8c1ffe5c900fb0da9512654bf249b5fc9269Deepanshu Gupta } 191145bc2d067faa3fb49b71e9e8c8c70b40564061aDeepanshu Gupta if (bestMatch == 0) { 192145bc2d067faa3fb49b71e9e8c8c70b40564061aDeepanshu Gupta return bestFont.mFont; 193145bc2d067faa3fb49b71e9e8c8c70b40564061aDeepanshu Gupta } 194145bc2d067faa3fb49b71e9e8c8c70b40564061aDeepanshu Gupta // Derive the font as required and add it to the list of Fonts. 195145bc2d067faa3fb49b71e9e8c8c70b40564061aDeepanshu Gupta deriveFont(bestFont, desiredStyle); 196145bc2d067faa3fb49b71e9e8c8c70b40564061aDeepanshu Gupta addFont(desiredStyle); 197145bc2d067faa3fb49b71e9e8c8c70b40564061aDeepanshu Gupta return desiredStyle.mFont; 198baef8c1ffe5c900fb0da9512654bf249b5fc9269Deepanshu Gupta } 199baef8c1ffe5c900fb0da9512654bf249b5fc9269Deepanshu Gupta 200ad69aee5ed503d9592c10a0f6d1a5b617d99e6c5Deepanshu Gupta public FontVariant getVariant() { 201ad69aee5ed503d9592c10a0f6d1a5b617d99e6c5Deepanshu Gupta return mVariant; 202ad69aee5ed503d9592c10a0f6d1a5b617d99e6c5Deepanshu Gupta } 203ad69aee5ed503d9592c10a0f6d1a5b617d99e6c5Deepanshu Gupta 204e644ff8d92ba040d11636be0fb6c433b52bcc6c2Deepanshu Gupta /** 205e644ff8d92ba040d11636be0fb6c433b52bcc6c2Deepanshu Gupta * Returns if the FontFamily should contain any fonts. If this returns true and 206145bc2d067faa3fb49b71e9e8c8c70b40564061aDeepanshu Gupta * {@link #getFont(int, boolean)} returns an empty list, it means that an error occurred while 207145bc2d067faa3fb49b71e9e8c8c70b40564061aDeepanshu Gupta * loading the fonts. However, some fonts are deliberately skipped, for example they are not 208145bc2d067faa3fb49b71e9e8c8c70b40564061aDeepanshu Gupta * bundled with the SDK. In such a case, this method returns false. 209e644ff8d92ba040d11636be0fb6c433b52bcc6c2Deepanshu Gupta */ 210e644ff8d92ba040d11636be0fb6c433b52bcc6c2Deepanshu Gupta public boolean isValid() { 211e644ff8d92ba040d11636be0fb6c433b52bcc6c2Deepanshu Gupta return mValid; 212e644ff8d92ba040d11636be0fb6c433b52bcc6c2Deepanshu Gupta } 213e644ff8d92ba040d11636be0fb6c433b52bcc6c2Deepanshu Gupta 2143c937cf5c730519e750cdee4d5fa61e2a593e33aDeepanshu Gupta /*package*/ static Font loadFont(String path) { 2153c937cf5c730519e750cdee4d5fa61e2a593e33aDeepanshu Gupta if (path.startsWith(SYSTEM_FONTS) ) { 2163c937cf5c730519e750cdee4d5fa61e2a593e33aDeepanshu Gupta String relativePath = path.substring(SYSTEM_FONTS.length()); 2173c937cf5c730519e750cdee4d5fa61e2a593e33aDeepanshu Gupta File f = new File(sFontLocation, relativePath); 2183c937cf5c730519e750cdee4d5fa61e2a593e33aDeepanshu Gupta 2193c937cf5c730519e750cdee4d5fa61e2a593e33aDeepanshu Gupta try { 2203c937cf5c730519e750cdee4d5fa61e2a593e33aDeepanshu Gupta return Font.createFont(Font.TRUETYPE_FONT, f); 2213c937cf5c730519e750cdee4d5fa61e2a593e33aDeepanshu Gupta } catch (Exception e) { 222d51834bdfad0cd3142ac464ab3a3b0db14f884c3Deepanshu Gupta if (path.endsWith(EXTENSION_OTF) && e instanceof FontFormatException) { 223b0d767dcf17dd393646b8fc3e8c9f46dfe12e230Deepanshu Gupta // If we aren't able to load an Open Type font, don't log a warning just yet. 224b0d767dcf17dd393646b8fc3e8c9f46dfe12e230Deepanshu Gupta // We wait for a case where font is being used. Only then we try to log the 225b0d767dcf17dd393646b8fc3e8c9f46dfe12e230Deepanshu Gupta // warning. 226b0d767dcf17dd393646b8fc3e8c9f46dfe12e230Deepanshu Gupta return null; 227b0d767dcf17dd393646b8fc3e8c9f46dfe12e230Deepanshu Gupta } 2283c937cf5c730519e750cdee4d5fa61e2a593e33aDeepanshu Gupta Bridge.getLog().fidelityWarning(LayoutLog.TAG_BROKEN, 2293c937cf5c730519e750cdee4d5fa61e2a593e33aDeepanshu Gupta String.format("Unable to load font %1$s", relativePath), 230b0d767dcf17dd393646b8fc3e8c9f46dfe12e230Deepanshu Gupta e, null); 2313c937cf5c730519e750cdee4d5fa61e2a593e33aDeepanshu Gupta } 2323c937cf5c730519e750cdee4d5fa61e2a593e33aDeepanshu Gupta } else { 2333c937cf5c730519e750cdee4d5fa61e2a593e33aDeepanshu Gupta Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED, 2343c937cf5c730519e750cdee4d5fa61e2a593e33aDeepanshu Gupta "Only platform fonts located in " + SYSTEM_FONTS + "can be loaded.", 235b0d767dcf17dd393646b8fc3e8c9f46dfe12e230Deepanshu Gupta null, null); 2363c937cf5c730519e750cdee4d5fa61e2a593e33aDeepanshu Gupta } 2373c937cf5c730519e750cdee4d5fa61e2a593e33aDeepanshu Gupta 2383c937cf5c730519e750cdee4d5fa61e2a593e33aDeepanshu Gupta return null; 2393c937cf5c730519e750cdee4d5fa61e2a593e33aDeepanshu Gupta } 2403c937cf5c730519e750cdee4d5fa61e2a593e33aDeepanshu Gupta 241b69ec7708b61535355d278ac0ea8f9a61540d1fbDeepanshu Gupta @Nullable 242b69ec7708b61535355d278ac0ea8f9a61540d1fbDeepanshu Gupta /*package*/ static String getFontLocation() { 243b69ec7708b61535355d278ac0ea8f9a61540d1fbDeepanshu Gupta return sFontLocation; 244b69ec7708b61535355d278ac0ea8f9a61540d1fbDeepanshu Gupta } 245ad69aee5ed503d9592c10a0f6d1a5b617d99e6c5Deepanshu Gupta 246baef8c1ffe5c900fb0da9512654bf249b5fc9269Deepanshu Gupta // ---- native methods ---- 247baef8c1ffe5c900fb0da9512654bf249b5fc9269Deepanshu Gupta 248baef8c1ffe5c900fb0da9512654bf249b5fc9269Deepanshu Gupta @LayoutlibDelegate 249ad69aee5ed503d9592c10a0f6d1a5b617d99e6c5Deepanshu Gupta /*package*/ static long nCreateFamily(String lang, int variant) { 250ad69aee5ed503d9592c10a0f6d1a5b617d99e6c5Deepanshu Gupta // TODO: support lang. This is required for japanese locale. 251baef8c1ffe5c900fb0da9512654bf249b5fc9269Deepanshu Gupta FontFamily_Delegate delegate = new FontFamily_Delegate(); 252ad69aee5ed503d9592c10a0f6d1a5b617d99e6c5Deepanshu Gupta // variant can be 0, 1 or 2. 253ad69aee5ed503d9592c10a0f6d1a5b617d99e6c5Deepanshu Gupta assert variant < 3; 254ad69aee5ed503d9592c10a0f6d1a5b617d99e6c5Deepanshu Gupta delegate.mVariant = FontVariant.values()[variant]; 255baef8c1ffe5c900fb0da9512654bf249b5fc9269Deepanshu Gupta if (sFontLocation != null) { 256baef8c1ffe5c900fb0da9512654bf249b5fc9269Deepanshu Gupta delegate.init(); 257baef8c1ffe5c900fb0da9512654bf249b5fc9269Deepanshu Gupta } else { 258baef8c1ffe5c900fb0da9512654bf249b5fc9269Deepanshu Gupta sPostInitDelegate.add(delegate); 259baef8c1ffe5c900fb0da9512654bf249b5fc9269Deepanshu Gupta } 260baef8c1ffe5c900fb0da9512654bf249b5fc9269Deepanshu Gupta return sManager.addNewDelegate(delegate); 261baef8c1ffe5c900fb0da9512654bf249b5fc9269Deepanshu Gupta } 262baef8c1ffe5c900fb0da9512654bf249b5fc9269Deepanshu Gupta 263baef8c1ffe5c900fb0da9512654bf249b5fc9269Deepanshu Gupta @LayoutlibDelegate 264baef8c1ffe5c900fb0da9512654bf249b5fc9269Deepanshu Gupta /*package*/ static void nUnrefFamily(long nativePtr) { 2659113968f9570b0c8ada2dec34fa6cf893da7c022Deepanshu Gupta // Removing the java reference for the object doesn't mean that it's freed for garbage 2669113968f9570b0c8ada2dec34fa6cf893da7c022Deepanshu Gupta // collection. Typeface_Delegate may still hold a reference for it. 267baef8c1ffe5c900fb0da9512654bf249b5fc9269Deepanshu Gupta sManager.removeJavaReferenceFor(nativePtr); 268baef8c1ffe5c900fb0da9512654bf249b5fc9269Deepanshu Gupta } 269baef8c1ffe5c900fb0da9512654bf249b5fc9269Deepanshu Gupta 270baef8c1ffe5c900fb0da9512654bf249b5fc9269Deepanshu Gupta @LayoutlibDelegate 271145bc2d067faa3fb49b71e9e8c8c70b40564061aDeepanshu Gupta /*package*/ static boolean nAddFont(long nativeFamily, final String path) { 272145bc2d067faa3fb49b71e9e8c8c70b40564061aDeepanshu Gupta final FontFamily_Delegate delegate = getDelegate(nativeFamily); 273baef8c1ffe5c900fb0da9512654bf249b5fc9269Deepanshu Gupta if (delegate != null) { 274baef8c1ffe5c900fb0da9512654bf249b5fc9269Deepanshu Gupta if (sFontLocation == null) { 275145bc2d067faa3fb49b71e9e8c8c70b40564061aDeepanshu Gupta delegate.mPostInitRunnables.add(new Runnable() { 276145bc2d067faa3fb49b71e9e8c8c70b40564061aDeepanshu Gupta @Override 277145bc2d067faa3fb49b71e9e8c8c70b40564061aDeepanshu Gupta public void run() { 278145bc2d067faa3fb49b71e9e8c8c70b40564061aDeepanshu Gupta delegate.addFont(path); 279145bc2d067faa3fb49b71e9e8c8c70b40564061aDeepanshu Gupta } 280145bc2d067faa3fb49b71e9e8c8c70b40564061aDeepanshu Gupta }); 281baef8c1ffe5c900fb0da9512654bf249b5fc9269Deepanshu Gupta return true; 282baef8c1ffe5c900fb0da9512654bf249b5fc9269Deepanshu Gupta } 283baef8c1ffe5c900fb0da9512654bf249b5fc9269Deepanshu Gupta return delegate.addFont(path); 284baef8c1ffe5c900fb0da9512654bf249b5fc9269Deepanshu Gupta } 285baef8c1ffe5c900fb0da9512654bf249b5fc9269Deepanshu Gupta return false; 286baef8c1ffe5c900fb0da9512654bf249b5fc9269Deepanshu Gupta } 287baef8c1ffe5c900fb0da9512654bf249b5fc9269Deepanshu Gupta 288ad69aee5ed503d9592c10a0f6d1a5b617d99e6c5Deepanshu Gupta @LayoutlibDelegate 289145bc2d067faa3fb49b71e9e8c8c70b40564061aDeepanshu Gupta /*package*/ static boolean nAddFontWeightStyle(long nativeFamily, final String path, 290145bc2d067faa3fb49b71e9e8c8c70b40564061aDeepanshu Gupta final int weight, final boolean isItalic) { 291145bc2d067faa3fb49b71e9e8c8c70b40564061aDeepanshu Gupta final FontFamily_Delegate delegate = getDelegate(nativeFamily); 292145bc2d067faa3fb49b71e9e8c8c70b40564061aDeepanshu Gupta if (delegate != null) { 293145bc2d067faa3fb49b71e9e8c8c70b40564061aDeepanshu Gupta if (sFontLocation == null) { 294145bc2d067faa3fb49b71e9e8c8c70b40564061aDeepanshu Gupta delegate.mPostInitRunnables.add(new Runnable() { 295145bc2d067faa3fb49b71e9e8c8c70b40564061aDeepanshu Gupta @Override 296145bc2d067faa3fb49b71e9e8c8c70b40564061aDeepanshu Gupta public void run() { 297145bc2d067faa3fb49b71e9e8c8c70b40564061aDeepanshu Gupta delegate.addFont(path, weight, isItalic); 298145bc2d067faa3fb49b71e9e8c8c70b40564061aDeepanshu Gupta } 299145bc2d067faa3fb49b71e9e8c8c70b40564061aDeepanshu Gupta }); 300145bc2d067faa3fb49b71e9e8c8c70b40564061aDeepanshu Gupta return true; 301145bc2d067faa3fb49b71e9e8c8c70b40564061aDeepanshu Gupta } 302145bc2d067faa3fb49b71e9e8c8c70b40564061aDeepanshu Gupta return delegate.addFont(path, weight, isItalic); 303145bc2d067faa3fb49b71e9e8c8c70b40564061aDeepanshu Gupta } 304145bc2d067faa3fb49b71e9e8c8c70b40564061aDeepanshu Gupta return false; 305145bc2d067faa3fb49b71e9e8c8c70b40564061aDeepanshu Gupta } 306145bc2d067faa3fb49b71e9e8c8c70b40564061aDeepanshu Gupta 307145bc2d067faa3fb49b71e9e8c8c70b40564061aDeepanshu Gupta @LayoutlibDelegate 308ad69aee5ed503d9592c10a0f6d1a5b617d99e6c5Deepanshu Gupta /*package*/ static boolean nAddFontFromAsset(long nativeFamily, AssetManager mgr, String path) { 309d51834bdfad0cd3142ac464ab3a3b0db14f884c3Deepanshu Gupta FontFamily_Delegate ffd = sManager.getDelegate(nativeFamily); 310d51834bdfad0cd3142ac464ab3a3b0db14f884c3Deepanshu Gupta ffd.mValid = true; 311d51834bdfad0cd3142ac464ab3a3b0db14f884c3Deepanshu Gupta if (mgr == null) { 312d51834bdfad0cd3142ac464ab3a3b0db14f884c3Deepanshu Gupta return false; 313d51834bdfad0cd3142ac464ab3a3b0db14f884c3Deepanshu Gupta } 314d51834bdfad0cd3142ac464ab3a3b0db14f884c3Deepanshu Gupta if (mgr instanceof BridgeAssetManager) { 315d51834bdfad0cd3142ac464ab3a3b0db14f884c3Deepanshu Gupta InputStream fontStream = null; 316d51834bdfad0cd3142ac464ab3a3b0db14f884c3Deepanshu Gupta try { 317d51834bdfad0cd3142ac464ab3a3b0db14f884c3Deepanshu Gupta AssetRepository assetRepository = ((BridgeAssetManager) mgr).getAssetRepository(); 318d51834bdfad0cd3142ac464ab3a3b0db14f884c3Deepanshu Gupta if (assetRepository == null) { 319d51834bdfad0cd3142ac464ab3a3b0db14f884c3Deepanshu Gupta Bridge.getLog().error(LayoutLog.TAG_MISSING_ASSET, "Asset not found: " + path, 320d51834bdfad0cd3142ac464ab3a3b0db14f884c3Deepanshu Gupta null); 321d51834bdfad0cd3142ac464ab3a3b0db14f884c3Deepanshu Gupta return false; 322d51834bdfad0cd3142ac464ab3a3b0db14f884c3Deepanshu Gupta } 323d51834bdfad0cd3142ac464ab3a3b0db14f884c3Deepanshu Gupta if (!assetRepository.isSupported()) { 324d51834bdfad0cd3142ac464ab3a3b0db14f884c3Deepanshu Gupta // Don't log any warnings on unsupported IDEs. 325d51834bdfad0cd3142ac464ab3a3b0db14f884c3Deepanshu Gupta return false; 326d51834bdfad0cd3142ac464ab3a3b0db14f884c3Deepanshu Gupta } 327d51834bdfad0cd3142ac464ab3a3b0db14f884c3Deepanshu Gupta // Check cache 328d51834bdfad0cd3142ac464ab3a3b0db14f884c3Deepanshu Gupta FontInfo fontInfo = sCache.get(path); 329d51834bdfad0cd3142ac464ab3a3b0db14f884c3Deepanshu Gupta if (fontInfo != null) { 330d51834bdfad0cd3142ac464ab3a3b0db14f884c3Deepanshu Gupta // renew the font's lease. 331d51834bdfad0cd3142ac464ab3a3b0db14f884c3Deepanshu Gupta sCache.put(path, fontInfo); 332d51834bdfad0cd3142ac464ab3a3b0db14f884c3Deepanshu Gupta ffd.addFont(fontInfo); 333d51834bdfad0cd3142ac464ab3a3b0db14f884c3Deepanshu Gupta return true; 334d51834bdfad0cd3142ac464ab3a3b0db14f884c3Deepanshu Gupta } 335d51834bdfad0cd3142ac464ab3a3b0db14f884c3Deepanshu Gupta fontStream = assetRepository.openAsset(path, AssetManager.ACCESS_STREAMING); 336d51834bdfad0cd3142ac464ab3a3b0db14f884c3Deepanshu Gupta if (fontStream == null) { 337d51834bdfad0cd3142ac464ab3a3b0db14f884c3Deepanshu Gupta Bridge.getLog().error(LayoutLog.TAG_MISSING_ASSET, "Asset not found: " + path, 338d51834bdfad0cd3142ac464ab3a3b0db14f884c3Deepanshu Gupta path); 339d51834bdfad0cd3142ac464ab3a3b0db14f884c3Deepanshu Gupta return false; 340d51834bdfad0cd3142ac464ab3a3b0db14f884c3Deepanshu Gupta } 341d51834bdfad0cd3142ac464ab3a3b0db14f884c3Deepanshu Gupta Font font = Font.createFont(Font.TRUETYPE_FONT, fontStream); 342d51834bdfad0cd3142ac464ab3a3b0db14f884c3Deepanshu Gupta fontInfo = new FontInfo(); 343d51834bdfad0cd3142ac464ab3a3b0db14f884c3Deepanshu Gupta fontInfo.mFont = font; 344d51834bdfad0cd3142ac464ab3a3b0db14f884c3Deepanshu Gupta fontInfo.mWeight = font.isBold() ? BOLD_FONT_WEIGHT : DEFAULT_FONT_WEIGHT; 345d51834bdfad0cd3142ac464ab3a3b0db14f884c3Deepanshu Gupta fontInfo.mIsItalic = font.isItalic(); 346d51834bdfad0cd3142ac464ab3a3b0db14f884c3Deepanshu Gupta ffd.addFont(fontInfo); 347d51834bdfad0cd3142ac464ab3a3b0db14f884c3Deepanshu Gupta return true; 348d51834bdfad0cd3142ac464ab3a3b0db14f884c3Deepanshu Gupta } catch (IOException e) { 349d51834bdfad0cd3142ac464ab3a3b0db14f884c3Deepanshu Gupta Bridge.getLog().error(LayoutLog.TAG_MISSING_ASSET, "Unable to load font " + path, e, 350d51834bdfad0cd3142ac464ab3a3b0db14f884c3Deepanshu Gupta path); 351d51834bdfad0cd3142ac464ab3a3b0db14f884c3Deepanshu Gupta } catch (FontFormatException e) { 352d51834bdfad0cd3142ac464ab3a3b0db14f884c3Deepanshu Gupta if (path.endsWith(EXTENSION_OTF)) { 353d51834bdfad0cd3142ac464ab3a3b0db14f884c3Deepanshu Gupta // otf fonts are not supported on the user's config (JRE version + OS) 354d51834bdfad0cd3142ac464ab3a3b0db14f884c3Deepanshu Gupta Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED, 355d51834bdfad0cd3142ac464ab3a3b0db14f884c3Deepanshu Gupta "OpenType fonts are not supported yet: " + path, null, path); 356d51834bdfad0cd3142ac464ab3a3b0db14f884c3Deepanshu Gupta } else { 357d51834bdfad0cd3142ac464ab3a3b0db14f884c3Deepanshu Gupta Bridge.getLog().error(LayoutLog.TAG_BROKEN, 358d51834bdfad0cd3142ac464ab3a3b0db14f884c3Deepanshu Gupta "Unable to load font " + path, e, path); 359d51834bdfad0cd3142ac464ab3a3b0db14f884c3Deepanshu Gupta } 360d51834bdfad0cd3142ac464ab3a3b0db14f884c3Deepanshu Gupta } finally { 361d51834bdfad0cd3142ac464ab3a3b0db14f884c3Deepanshu Gupta if (fontStream != null) { 362d51834bdfad0cd3142ac464ab3a3b0db14f884c3Deepanshu Gupta try { 363d51834bdfad0cd3142ac464ab3a3b0db14f884c3Deepanshu Gupta fontStream.close(); 364d51834bdfad0cd3142ac464ab3a3b0db14f884c3Deepanshu Gupta } catch (IOException ignored) { 365d51834bdfad0cd3142ac464ab3a3b0db14f884c3Deepanshu Gupta } 366d51834bdfad0cd3142ac464ab3a3b0db14f884c3Deepanshu Gupta } 367d51834bdfad0cd3142ac464ab3a3b0db14f884c3Deepanshu Gupta } 368d51834bdfad0cd3142ac464ab3a3b0db14f884c3Deepanshu Gupta return false; 369d51834bdfad0cd3142ac464ab3a3b0db14f884c3Deepanshu Gupta } 370d51834bdfad0cd3142ac464ab3a3b0db14f884c3Deepanshu Gupta // This should never happen. AssetManager is a final class (from user's perspective), and 371d51834bdfad0cd3142ac464ab3a3b0db14f884c3Deepanshu Gupta // we've replaced every creation of AssetManager with our implementation. We create an 372d51834bdfad0cd3142ac464ab3a3b0db14f884c3Deepanshu Gupta // exception and log it, but continue with rest of the rendering, without loading this font. 373d51834bdfad0cd3142ac464ab3a3b0db14f884c3Deepanshu Gupta Bridge.getLog().error(LayoutLog.TAG_BROKEN, 374d51834bdfad0cd3142ac464ab3a3b0db14f884c3Deepanshu Gupta "You have found a bug in the rendering library. Please file a bug at b.android.com.", 375d51834bdfad0cd3142ac464ab3a3b0db14f884c3Deepanshu Gupta new RuntimeException("Asset Manager is not an instance of BridgeAssetManager"), 376d51834bdfad0cd3142ac464ab3a3b0db14f884c3Deepanshu Gupta null); 377ad69aee5ed503d9592c10a0f6d1a5b617d99e6c5Deepanshu Gupta return false; 378ad69aee5ed503d9592c10a0f6d1a5b617d99e6c5Deepanshu Gupta } 379ad69aee5ed503d9592c10a0f6d1a5b617d99e6c5Deepanshu Gupta 3803c937cf5c730519e750cdee4d5fa61e2a593e33aDeepanshu Gupta 3813c937cf5c730519e750cdee4d5fa61e2a593e33aDeepanshu Gupta // ---- private helper methods ---- 3823c937cf5c730519e750cdee4d5fa61e2a593e33aDeepanshu Gupta 383baef8c1ffe5c900fb0da9512654bf249b5fc9269Deepanshu Gupta private void init() { 384145bc2d067faa3fb49b71e9e8c8c70b40564061aDeepanshu Gupta for (Runnable postInitRunnable : mPostInitRunnables) { 385145bc2d067faa3fb49b71e9e8c8c70b40564061aDeepanshu Gupta postInitRunnable.run(); 386baef8c1ffe5c900fb0da9512654bf249b5fc9269Deepanshu Gupta } 387145bc2d067faa3fb49b71e9e8c8c70b40564061aDeepanshu Gupta mPostInitRunnables = null; 388baef8c1ffe5c900fb0da9512654bf249b5fc9269Deepanshu Gupta } 389baef8c1ffe5c900fb0da9512654bf249b5fc9269Deepanshu Gupta 390145bc2d067faa3fb49b71e9e8c8c70b40564061aDeepanshu Gupta private boolean addFont(@NonNull String path) { 391145bc2d067faa3fb49b71e9e8c8c70b40564061aDeepanshu Gupta return addFont(path, DEFAULT_FONT_WEIGHT, path.endsWith(FONT_SUFFIX_ITALIC)); 392145bc2d067faa3fb49b71e9e8c8c70b40564061aDeepanshu Gupta } 393145bc2d067faa3fb49b71e9e8c8c70b40564061aDeepanshu Gupta 394145bc2d067faa3fb49b71e9e8c8c70b40564061aDeepanshu Gupta private boolean addFont(@NonNull String path, int weight, boolean isItalic) { 3950e4be2540984235a0a7b84ea0466ef3c92d27b07Deepanshu Gupta if (path.startsWith(SYSTEM_FONTS) && 3960e4be2540984235a0a7b84ea0466ef3c92d27b07Deepanshu Gupta !SDK_FONTS.contains(path.substring(SYSTEM_FONTS.length()))) { 3970e4be2540984235a0a7b84ea0466ef3c92d27b07Deepanshu Gupta return mValid = false; 3980e4be2540984235a0a7b84ea0466ef3c92d27b07Deepanshu Gupta } 3990e4be2540984235a0a7b84ea0466ef3c92d27b07Deepanshu Gupta // Set valid to true, even if the font fails to load. 4000e4be2540984235a0a7b84ea0466ef3c92d27b07Deepanshu Gupta mValid = true; 401baef8c1ffe5c900fb0da9512654bf249b5fc9269Deepanshu Gupta Font font = loadFont(path); 402baef8c1ffe5c900fb0da9512654bf249b5fc9269Deepanshu Gupta if (font == null) { 403baef8c1ffe5c900fb0da9512654bf249b5fc9269Deepanshu Gupta return false; 404baef8c1ffe5c900fb0da9512654bf249b5fc9269Deepanshu Gupta } 405baef8c1ffe5c900fb0da9512654bf249b5fc9269Deepanshu Gupta FontInfo fontInfo = new FontInfo(); 406baef8c1ffe5c900fb0da9512654bf249b5fc9269Deepanshu Gupta fontInfo.mFont = font; 407145bc2d067faa3fb49b71e9e8c8c70b40564061aDeepanshu Gupta fontInfo.mWeight = weight; 408145bc2d067faa3fb49b71e9e8c8c70b40564061aDeepanshu Gupta fontInfo.mIsItalic = isItalic; 409145bc2d067faa3fb49b71e9e8c8c70b40564061aDeepanshu Gupta addFont(fontInfo); 410145bc2d067faa3fb49b71e9e8c8c70b40564061aDeepanshu Gupta return true; 411145bc2d067faa3fb49b71e9e8c8c70b40564061aDeepanshu Gupta } 412145bc2d067faa3fb49b71e9e8c8c70b40564061aDeepanshu Gupta 413145bc2d067faa3fb49b71e9e8c8c70b40564061aDeepanshu Gupta private boolean addFont(@NonNull FontInfo fontInfo) { 414145bc2d067faa3fb49b71e9e8c8c70b40564061aDeepanshu Gupta int weight = fontInfo.mWeight; 415145bc2d067faa3fb49b71e9e8c8c70b40564061aDeepanshu Gupta boolean isItalic = fontInfo.mIsItalic; 416145bc2d067faa3fb49b71e9e8c8c70b40564061aDeepanshu Gupta // The list is usually just two fonts big. So iterating over all isn't as bad as it looks. 417145bc2d067faa3fb49b71e9e8c8c70b40564061aDeepanshu Gupta // It's biggest for roboto where the size is 12. 418145bc2d067faa3fb49b71e9e8c8c70b40564061aDeepanshu Gupta for (FontInfo font : mFonts) { 419145bc2d067faa3fb49b71e9e8c8c70b40564061aDeepanshu Gupta if (font.mWeight == weight && font.mIsItalic == isItalic) { 420145bc2d067faa3fb49b71e9e8c8c70b40564061aDeepanshu Gupta return false; 421145bc2d067faa3fb49b71e9e8c8c70b40564061aDeepanshu Gupta } 422145bc2d067faa3fb49b71e9e8c8c70b40564061aDeepanshu Gupta } 423baef8c1ffe5c900fb0da9512654bf249b5fc9269Deepanshu Gupta mFonts.add(fontInfo); 424baef8c1ffe5c900fb0da9512654bf249b5fc9269Deepanshu Gupta return true; 425baef8c1ffe5c900fb0da9512654bf249b5fc9269Deepanshu Gupta } 426145bc2d067faa3fb49b71e9e8c8c70b40564061aDeepanshu Gupta 427145bc2d067faa3fb49b71e9e8c8c70b40564061aDeepanshu Gupta /** 428145bc2d067faa3fb49b71e9e8c8c70b40564061aDeepanshu Gupta * Compute matching metric between two styles - 0 is an exact match. 429145bc2d067faa3fb49b71e9e8c8c70b40564061aDeepanshu Gupta */ 430145bc2d067faa3fb49b71e9e8c8c70b40564061aDeepanshu Gupta private static int computeMatch(@NonNull FontInfo font1, @NonNull FontInfo font2) { 431145bc2d067faa3fb49b71e9e8c8c70b40564061aDeepanshu Gupta int score = Math.abs(font1.mWeight - font2.mWeight); 432145bc2d067faa3fb49b71e9e8c8c70b40564061aDeepanshu Gupta if (font1.mIsItalic != font2.mIsItalic) { 433145bc2d067faa3fb49b71e9e8c8c70b40564061aDeepanshu Gupta score += 200; 434145bc2d067faa3fb49b71e9e8c8c70b40564061aDeepanshu Gupta } 435145bc2d067faa3fb49b71e9e8c8c70b40564061aDeepanshu Gupta return score; 436145bc2d067faa3fb49b71e9e8c8c70b40564061aDeepanshu Gupta } 437145bc2d067faa3fb49b71e9e8c8c70b40564061aDeepanshu Gupta 438145bc2d067faa3fb49b71e9e8c8c70b40564061aDeepanshu Gupta /** 439145bc2d067faa3fb49b71e9e8c8c70b40564061aDeepanshu Gupta * Try to derive a font from {@code srcFont} for the style in {@code outFont}. 440145bc2d067faa3fb49b71e9e8c8c70b40564061aDeepanshu Gupta * <p/> 441145bc2d067faa3fb49b71e9e8c8c70b40564061aDeepanshu Gupta * {@code outFont} is updated to reflect the style of the derived font. 442145bc2d067faa3fb49b71e9e8c8c70b40564061aDeepanshu Gupta * @param srcFont the source font 443145bc2d067faa3fb49b71e9e8c8c70b40564061aDeepanshu Gupta * @param outFont contains the desired font style. Updated to contain the derived font and 444145bc2d067faa3fb49b71e9e8c8c70b40564061aDeepanshu Gupta * its style 445145bc2d067faa3fb49b71e9e8c8c70b40564061aDeepanshu Gupta * @return outFont 446145bc2d067faa3fb49b71e9e8c8c70b40564061aDeepanshu Gupta */ 447145bc2d067faa3fb49b71e9e8c8c70b40564061aDeepanshu Gupta @NonNull 448145bc2d067faa3fb49b71e9e8c8c70b40564061aDeepanshu Gupta private FontInfo deriveFont(@NonNull FontInfo srcFont, @NonNull FontInfo outFont) { 449145bc2d067faa3fb49b71e9e8c8c70b40564061aDeepanshu Gupta int desiredWeight = outFont.mWeight; 450145bc2d067faa3fb49b71e9e8c8c70b40564061aDeepanshu Gupta int srcWeight = srcFont.mWeight; 451145bc2d067faa3fb49b71e9e8c8c70b40564061aDeepanshu Gupta Font derivedFont = srcFont.mFont; 452145bc2d067faa3fb49b71e9e8c8c70b40564061aDeepanshu Gupta // Embolden the font if required. 453145bc2d067faa3fb49b71e9e8c8c70b40564061aDeepanshu Gupta if (desiredWeight >= BOLD_FONT_WEIGHT && desiredWeight - srcWeight > BOLD_FONT_WEIGHT_DELTA / 2) { 454145bc2d067faa3fb49b71e9e8c8c70b40564061aDeepanshu Gupta derivedFont = derivedFont.deriveFont(Font.BOLD); 455145bc2d067faa3fb49b71e9e8c8c70b40564061aDeepanshu Gupta srcWeight += BOLD_FONT_WEIGHT_DELTA; 456145bc2d067faa3fb49b71e9e8c8c70b40564061aDeepanshu Gupta } 457145bc2d067faa3fb49b71e9e8c8c70b40564061aDeepanshu Gupta // Italicize the font if required. 458145bc2d067faa3fb49b71e9e8c8c70b40564061aDeepanshu Gupta if (outFont.mIsItalic && !srcFont.mIsItalic) { 459145bc2d067faa3fb49b71e9e8c8c70b40564061aDeepanshu Gupta derivedFont = derivedFont.deriveFont(Font.ITALIC); 460145bc2d067faa3fb49b71e9e8c8c70b40564061aDeepanshu Gupta } else if (outFont.mIsItalic != srcFont.mIsItalic) { 461145bc2d067faa3fb49b71e9e8c8c70b40564061aDeepanshu Gupta // The desired font is plain, but the src font is italics. We can't convert it back. So 462145bc2d067faa3fb49b71e9e8c8c70b40564061aDeepanshu Gupta // we update the value to reflect the true style of the font we're deriving. 463145bc2d067faa3fb49b71e9e8c8c70b40564061aDeepanshu Gupta outFont.mIsItalic = srcFont.mIsItalic; 464145bc2d067faa3fb49b71e9e8c8c70b40564061aDeepanshu Gupta } 465145bc2d067faa3fb49b71e9e8c8c70b40564061aDeepanshu Gupta outFont.mFont = derivedFont; 466145bc2d067faa3fb49b71e9e8c8c70b40564061aDeepanshu Gupta outFont.mWeight = srcWeight; 467145bc2d067faa3fb49b71e9e8c8c70b40564061aDeepanshu Gupta // No need to update mIsItalics, as it's already been handled above. 468145bc2d067faa3fb49b71e9e8c8c70b40564061aDeepanshu Gupta return outFont; 469145bc2d067faa3fb49b71e9e8c8c70b40564061aDeepanshu Gupta } 470baef8c1ffe5c900fb0da9512654bf249b5fc9269Deepanshu Gupta} 471