Skip to content

Commit

Permalink
custom fonts support The Android Way (#24595)
Browse files Browse the repository at this point in the history
Summary:
In #23865, RN introduced support for custom fonts the Android Way. But it introduced performance regression because it'll lookup for a font using getIdentifier() every time fontFamily changed. This PR fixes regression by requiring custom fonts to be listed in **fonts** array, and populating **mTypeCache** at first use using the list.

[Android] [Changed] - Require custom fonts to list in **fonts** array. Fixes performance regression.
Pull Request resolved: #24595

Reviewed By: mdvacca

Differential Revision: D15184590

Pulled By: fkgozali

fbshipit-source-id: e3feb2396609583ebc95101130186a1f5af931da
  • Loading branch information
dulmandakh authored and facebook-github-bot committed May 8, 2019
1 parent 661b3b6 commit fd6386a
Show file tree
Hide file tree
Showing 8 changed files with 56 additions and 14 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@

package com.facebook.react.uiapp;

import android.app.Activity;
import android.os.Bundle;

import com.facebook.react.ReactActivity;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,11 @@
import com.facebook.react.ReactNativeHost;
import com.facebook.react.ReactPackage;
import com.facebook.react.shell.MainReactPackage;
import com.facebook.react.views.text.ReactFontManager;

import java.util.Arrays;
import java.util.List;

import javax.annotation.Nullable;

public class RNTesterApplication extends Application implements ReactApplication {
private final ReactNativeHost mReactNativeHost = new ReactNativeHost(this) {
@Override
Expand All @@ -29,7 +28,7 @@ public String getJSMainModuleName() {
}

@Override
public @Nullable String getBundleAssetName() {
public String getBundleAssetName() {
return "RNTesterApp.android.bundle";
}

Expand All @@ -46,6 +45,12 @@ public List<ReactPackage> getPackages() {
}
};

@Override
public void onCreate() {
ReactFontManager.getInstance().addCustomFont(this, "Srisakdi", R.font.srisakdi);
super.onCreate();
}

@Override
public ReactNativeHost getReactNativeHost() {
return mReactNativeHost;
Expand Down
5 changes: 5 additions & 0 deletions RNTester/android/app/src/main/res/font/srisakdi.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<font-family xmlns:app="http://schemas.android.com/apk/res-auto">
<font app:fontStyle="normal" app:fontWeight="400" app:font="@font/srisakdi_regular"/>
<font app:fontStyle="normal" app:fontWeight="700" app:font="@font/srisakdi_bold" />
</font-family>
Binary file not shown.
Binary file not shown.
8 changes: 8 additions & 0 deletions RNTester/js/TextExample.android.js
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,14 @@ class TextExample extends React.Component<{}> {
<Text style={{fontFamily: 'notoserif', fontStyle: 'italic'}}>
NotoSerif Italic (Missing Font file)
</Text>
<Text style={{fontFamily: 'Srisakdi'}}>Srisakdi Regular</Text>
<Text
style={{
fontFamily: 'Srisakdi',
fontWeight: 'bold',
}}>
Srisakdi Bold
</Text>
</View>
</View>
</RNTesterBlock>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,15 @@

package com.facebook.react.views.text;

import javax.annotation.Nullable;

import android.content.res.AssetManager;
import android.graphics.Paint;
import android.graphics.Typeface;
import android.text.TextPaint;
import android.text.style.MetricAffectingSpan;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;

public class CustomStyleSpan extends MetricAffectingSpan implements ReactSpan {

/**
Expand All @@ -39,7 +40,7 @@ public CustomStyleSpan(
int fontStyle,
int fontWeight,
@Nullable String fontFamily,
AssetManager assetManager) {
@NonNull AssetManager assetManager) {
mStyle = fontStyle;
mWeight = fontWeight;
mFontFamily = fontFamily;
Expand All @@ -52,7 +53,7 @@ public void updateDrawState(TextPaint ds) {
}

@Override
public void updateMeasureState(TextPaint paint) {
public void updateMeasureState(@NonNull TextPaint paint) {
apply(paint, mStyle, mWeight, mFontFamily, mAssetManager);
}

Expand Down Expand Up @@ -116,5 +117,4 @@ private static void apply(
}
paint.setSubpixelText(true);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,18 @@

package com.facebook.react.views.text;

import javax.annotation.Nullable;

import java.util.HashMap;
import java.util.Map;

import android.content.Context;
import android.content.res.AssetManager;
import android.graphics.Typeface;
import android.util.SparseArray;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.content.res.ResourcesCompat;

/**
* 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
Expand All @@ -36,10 +39,12 @@ public class ReactFontManager {

private static ReactFontManager sReactFontManagerInstance;

private Map<String, FontFamily> mFontCache;
final private Map<String, FontFamily> mFontCache;
final private Map<String, Typeface> mCustomTypefaceCache;

private ReactFontManager() {
mFontCache = new HashMap<>();
mCustomTypefaceCache = new HashMap<>();
}

public static ReactFontManager getInstance() {
Expand All @@ -49,8 +54,7 @@ public static ReactFontManager getInstance() {
return sReactFontManagerInstance;
}

public
@Nullable Typeface getTypeface(
public @Nullable Typeface getTypeface(
String fontFamilyName,
int style,
AssetManager assetManager) {
Expand All @@ -60,6 +64,13 @@ public static ReactFontManager getInstance() {
mFontCache.put(fontFamilyName, fontFamily);
}

if(mCustomTypefaceCache.containsKey(fontFamilyName)) {
return Typeface.create(
mCustomTypefaceCache.get(fontFamilyName),
style
);
}

Typeface typeface = fontFamily.getTypeface(style);
if (typeface == null) {
typeface = createTypeface(fontFamilyName, style, assetManager);
Expand All @@ -71,6 +82,20 @@ public static ReactFontManager getInstance() {
return typeface;
}

/*
* This method allows you to load custom fonts from res/font folder as provided font family name.
* Fonts may be one of .ttf, .otf or XML (https://developer.android.com/guide/topics/ui/look-and-feel/fonts-in-xml).
* To support multiple font styles or weights, you must provide a font in XML format.
*
* ReactFontManager.getInstance().addCustomFont(this, "Srisakdi", R.font.srisakdi);
*/
public void addCustomFont(@NonNull Context context, @NonNull String fontFamily, int fontId) {
Typeface font = ResourcesCompat.getFont(context, fontId);
if (font != null) {
mCustomTypefaceCache.put(fontFamily, font);
}
}

/**
* Add additional font family, or replace the exist one in the font memory cache.
* @param style
Expand Down

0 comments on commit fd6386a

Please sign in to comment.