/** * Copyright (c) 2015-present, Facebook, Inc. All rights reserved. * <p/> * This source code is licensed under the BSD-style license found in the LICENSE file in the root * directory of this source tree. An additional grant of patent rights can be found in the PATENTS * file in the same directory. */ package com.facebook.react.views.text; import javax.annotation.Nullable; import java.util.HashMap; import java.util.Map; import android.content.res.AssetManager; import android.graphics.Typeface; import android.util.SparseArray; /** * Class responsible to load and cache Typeface objects. It will first try to load typefaces inside * the assets/fonts folder and if it doesn't find the right Typeface in that folder will fall back * on the best matching system Typeface The supported custom fonts extensions are .ttf and .otf. For * each font family the bold, italic and bold_italic variants are supported. Given a "family" font * family the files in the assets/fonts folder need to be family.ttf(.otf) family_bold.ttf(.otf) * family_italic.ttf(.otf) and family_bold_italic.ttf(.otf) */ public class ReactFontManager { private static final String[] EXTENSIONS = { "", "_bold", "_italic", "_bold_italic"}; private static final String[] FILE_EXTENSIONS = {".ttf", ".otf"}; private static final String FONTS_ASSET_PATH = "fonts/"; private static ReactFontManager sReactFontManagerInstance; private Map<String, FontFamily> mFontCache; private ReactFontManager() { mFontCache = new HashMap<>(); } public static ReactFontManager getInstance() { if (sReactFontManagerInstance == null) { sReactFontManagerInstance = new ReactFontManager(); } return sReactFontManagerInstance; } public @Nullable Typeface getTypeface( String fontFamilyName, int style, AssetManager assetManager) { FontFamily fontFamily = mFontCache.get(fontFamilyName); if (fontFamily == null) { fontFamily = new FontFamily(); mFontCache.put(fontFamilyName, fontFamily); } Typeface typeface = fontFamily.getTypeface(style); if (typeface == null) { typeface = createTypeface(fontFamilyName, style, assetManager); if (typeface != null) { fontFamily.setTypeface(style, typeface); } } return typeface; } /** * Add additional font family, or replace the exist one in the font memory cache. * @param style * @see {@link Typeface#DEFAULT} * @see {@link Typeface#BOLD} * @see {@link Typeface#ITALIC} * @see {@link Typeface#BOLD_ITALIC} */ public void setTypeface(String fontFamilyName, int style, Typeface typeface) { if (typeface != null) { FontFamily fontFamily = mFontCache.get(fontFamilyName); if (fontFamily == null) { fontFamily = new FontFamily(); mFontCache.put(fontFamilyName, fontFamily); } fontFamily.setTypeface(style, typeface); } } private static @Nullable Typeface createTypeface( String fontFamilyName, int style, AssetManager assetManager) { String extension = EXTENSIONS[style]; for (String fileExtension : FILE_EXTENSIONS) { String fileName = new StringBuilder() .append(FONTS_ASSET_PATH) .append(fontFamilyName) .append(extension) .append(fileExtension) .toString(); try { return Typeface.createFromAsset(assetManager, fileName); } catch (RuntimeException e) { // unfortunately Typeface.createFromAsset throws an exception instead of returning null // if the typeface doesn't exist } } return Typeface.create(fontFamilyName, style); } private static class FontFamily { private SparseArray<Typeface> mTypefaceSparseArray; private FontFamily() { mTypefaceSparseArray = new SparseArray<>(4); } public Typeface getTypeface(int style) { return mTypefaceSparseArray.get(style); } public void setTypeface(int style, Typeface typeface) { mTypefaceSparseArray.put(style, typeface); } } }