mirror of
https://github.com/facebook/react-native.git
synced 2025-11-01 09:14:26 +00:00
Add Android support for fontVariant prop (#27006)
Summary: Android was missing support for the `fontVariant` prop in TextViews, this PR adds that. ## Changelog [Android] [Added] - Add Android support for fontVariant prop Pull Request resolved: https://github.com/facebook/react-native/pull/27006 Test Plan: Since I can't get RNTester to work locally (it crashes when loading `libyoga.so` on `No implementation found for long com.facebook.yoga.YogaNative.jni_YGConfigNew()`), I'll post some screenshots below of our app showing the difference. We are using a slightly different [version](https://github.com/getdelta/react-native/commit/10cafcaa0798e5dbe8b56d461885fa84c6953739) of this commit, since we're still on 0.60, but the gist remains the same when rebased on master. Before:  After:  Differential Revision: D18179642 Pulled By: mdvacca fbshipit-source-id: 03a050aa76e7bafa0343354dfa778cf74af5abd2
This commit is contained in:
committed by
Facebook Github Bot
parent
6ebd3b046e
commit
c2c4b43dfe
@@ -83,6 +83,7 @@ public class ViewProps {
|
||||
public static final String FONT_SIZE = "fontSize";
|
||||
public static final String FONT_WEIGHT = "fontWeight";
|
||||
public static final String FONT_STYLE = "fontStyle";
|
||||
public static final String FONT_VARIANT = "fontVariant";
|
||||
public static final String FONT_FAMILY = "fontFamily";
|
||||
public static final String LINE_HEIGHT = "lineHeight";
|
||||
public static final String LETTER_SPACING = "letterSpacing";
|
||||
|
||||
@@ -10,6 +10,7 @@ package com.facebook.react.views.text;
|
||||
import android.content.res.AssetManager;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.Typeface;
|
||||
import android.os.Build;
|
||||
import android.text.TextPaint;
|
||||
import android.text.style.MetricAffectingSpan;
|
||||
import androidx.annotation.NonNull;
|
||||
@@ -32,27 +33,30 @@ public class CustomStyleSpan extends MetricAffectingSpan implements ReactSpan {
|
||||
|
||||
private final int mStyle;
|
||||
private final int mWeight;
|
||||
private final @Nullable String mFeatureSettings;
|
||||
private final @Nullable String mFontFamily;
|
||||
|
||||
public CustomStyleSpan(
|
||||
int fontStyle,
|
||||
int fontWeight,
|
||||
@Nullable String fontFeatureSettings,
|
||||
@Nullable String fontFamily,
|
||||
@NonNull AssetManager assetManager) {
|
||||
mStyle = fontStyle;
|
||||
mWeight = fontWeight;
|
||||
mFeatureSettings = fontFeatureSettings;
|
||||
mFontFamily = fontFamily;
|
||||
mAssetManager = assetManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateDrawState(TextPaint ds) {
|
||||
apply(ds, mStyle, mWeight, mFontFamily, mAssetManager);
|
||||
apply(ds, mStyle, mWeight, mFeatureSettings, mFontFamily, mAssetManager);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateMeasureState(@NonNull TextPaint paint) {
|
||||
apply(paint, mStyle, mWeight, mFontFamily, mAssetManager);
|
||||
apply(paint, mStyle, mWeight, mFeatureSettings, mFontFamily, mAssetManager);
|
||||
}
|
||||
|
||||
/** Returns {@link Typeface#NORMAL} or {@link Typeface#ITALIC}. */
|
||||
@@ -71,9 +75,17 @@ public class CustomStyleSpan extends MetricAffectingSpan implements ReactSpan {
|
||||
}
|
||||
|
||||
private static void apply(
|
||||
Paint paint, int style, int weight, @Nullable String family, AssetManager assetManager) {
|
||||
Paint paint,
|
||||
int style,
|
||||
int weight,
|
||||
@Nullable String fontFeatureSettings,
|
||||
@Nullable String family,
|
||||
AssetManager assetManager) {
|
||||
Typeface typeface = ReactTypefaceUtils.applyStyles(
|
||||
paint.getTypeface(), style, weight, family, assetManager);
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
paint.setFontFeatureSettings(fontFeatureSettings);
|
||||
}
|
||||
paint.setTypeface(typeface);
|
||||
paint.setSubpixelText(true);
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@ import android.view.Gravity;
|
||||
import androidx.annotation.Nullable;
|
||||
import com.facebook.infer.annotation.Assertions;
|
||||
import com.facebook.react.bridge.JSApplicationIllegalArgumentException;
|
||||
import com.facebook.react.bridge.ReadableArray;
|
||||
import com.facebook.react.bridge.ReadableMap;
|
||||
import com.facebook.react.uimanager.IllegalViewOperationException;
|
||||
import com.facebook.react.uimanager.LayoutShadowNode;
|
||||
@@ -33,6 +34,7 @@ import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* {@link ReactShadowNode} abstract class for spannable text nodes.
|
||||
@@ -195,6 +197,7 @@ public abstract class ReactBaseTextShadowNode extends LayoutShadowNode {
|
||||
new CustomStyleSpan(
|
||||
textShadowNode.mFontStyle,
|
||||
textShadowNode.mFontWeight,
|
||||
textShadowNode.mFontFeatureSettings,
|
||||
textShadowNode.mFontFamily,
|
||||
textShadowNode.getThemedContext().getAssets())));
|
||||
}
|
||||
@@ -357,6 +360,11 @@ public abstract class ReactBaseTextShadowNode extends LayoutShadowNode {
|
||||
*/
|
||||
protected @Nullable String mFontFamily = null;
|
||||
|
||||
/**
|
||||
* @see android.graphics.Paint#setFontFeatureSettings
|
||||
*/
|
||||
protected @Nullable String mFontFeatureSettings = null;
|
||||
|
||||
protected boolean mContainsImages = false;
|
||||
protected Map<Integer, ReactShadowNode> mInlineViews;
|
||||
|
||||
@@ -483,6 +491,16 @@ public abstract class ReactBaseTextShadowNode extends LayoutShadowNode {
|
||||
}
|
||||
}
|
||||
|
||||
@ReactProp(name = ViewProps.FONT_VARIANT)
|
||||
public void setFontVariant(@Nullable ReadableArray fontVariantArray) {
|
||||
String fontFeatureSettings = ReactTypefaceUtils.parseFontVariant(fontVariantArray);
|
||||
|
||||
if (!Objects.equals(fontFeatureSettings, mFontFeatureSettings)) {
|
||||
mFontFeatureSettings = fontFeatureSettings;
|
||||
markUpdated();
|
||||
}
|
||||
}
|
||||
|
||||
@ReactProp(name = ViewProps.FONT_STYLE)
|
||||
public void setFontStyle(@Nullable String fontStyleString) {
|
||||
int fontStyle = ReactTypefaceUtils.parseFontStyle(fontStyleString);
|
||||
|
||||
@@ -13,6 +13,11 @@ import android.graphics.Typeface;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.facebook.react.bridge.ReadableArray;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class ReactTypefaceUtils {
|
||||
public static final int UNSET = -1;
|
||||
|
||||
@@ -38,6 +43,36 @@ public class ReactTypefaceUtils {
|
||||
return fontStyle;
|
||||
}
|
||||
|
||||
public static @Nullable String parseFontVariant(@Nullable ReadableArray fontVariantArray) {
|
||||
if (fontVariantArray == null || fontVariantArray.size() == 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
List<String> features = new ArrayList<>();
|
||||
for (int i = 0; i < fontVariantArray.size(); i++) {
|
||||
// see https://docs.microsoft.com/en-us/typography/opentype/spec/featurelist
|
||||
switch (fontVariantArray.getString(i)) {
|
||||
case "small-caps":
|
||||
features.add("'smcp'");
|
||||
break;
|
||||
case "oldstyle-nums":
|
||||
features.add("'onum'");
|
||||
break;
|
||||
case "lining-nums":
|
||||
features.add("'lnum'");
|
||||
break;
|
||||
case "tabular-nums":
|
||||
features.add("'tnum'");
|
||||
break;
|
||||
case "proportional-nums":
|
||||
features.add("'pnum'");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return String.join(", ", features);
|
||||
}
|
||||
|
||||
public static Typeface applyStyles(@Nullable Typeface typeface,
|
||||
int style, int weight, @Nullable String family, AssetManager assetManager) {
|
||||
int oldStyle;
|
||||
|
||||
@@ -13,6 +13,7 @@ import android.text.Layout;
|
||||
import android.view.Gravity;
|
||||
import androidx.annotation.Nullable;
|
||||
import com.facebook.react.bridge.JSApplicationIllegalArgumentException;
|
||||
import com.facebook.react.bridge.ReadableArray;
|
||||
import com.facebook.react.bridge.ReadableMap;
|
||||
import com.facebook.react.uimanager.PixelUtil;
|
||||
import com.facebook.react.uimanager.ReactStylesDiffMap;
|
||||
@@ -92,6 +93,11 @@ public class TextAttributeProps {
|
||||
*/
|
||||
protected @Nullable String mFontFamily = null;
|
||||
|
||||
/**
|
||||
* @see android.graphics.Paint#setFontFeatureSettings
|
||||
*/
|
||||
protected @Nullable String mFontFeatureSettings = null;
|
||||
|
||||
protected boolean mContainsImages = false;
|
||||
protected float mHeightOfTallestInlineImage = Float.NaN;
|
||||
|
||||
@@ -114,6 +120,7 @@ public class TextAttributeProps {
|
||||
setFontFamily(getStringProp(ViewProps.FONT_FAMILY));
|
||||
setFontWeight(getStringProp(ViewProps.FONT_WEIGHT));
|
||||
setFontStyle(getStringProp(ViewProps.FONT_STYLE));
|
||||
setFontVariant(getArrayProp(ViewProps.FONT_VARIANT));
|
||||
setIncludeFontPadding(getBooleanProp(ViewProps.INCLUDE_FONT_PADDING, true));
|
||||
setTextDecorationLine(getStringProp(ViewProps.TEXT_DECORATION_LINE));
|
||||
setTextBreakStrategy(getStringProp(ViewProps.TEXT_BREAK_STRATEGY));
|
||||
@@ -155,6 +162,14 @@ public class TextAttributeProps {
|
||||
}
|
||||
}
|
||||
|
||||
private @Nullable ReadableArray getArrayProp(String name) {
|
||||
if (mProps.hasKey(name)) {
|
||||
return mProps.getArray(name);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// Returns a line height which takes into account the requested line height
|
||||
// and the height of the inline images.
|
||||
public float getEffectiveLineHeight() {
|
||||
@@ -280,6 +295,10 @@ public class TextAttributeProps {
|
||||
mFontFamily = fontFamily;
|
||||
}
|
||||
|
||||
public void setFontVariant(@Nullable ReadableArray fontVariant) {
|
||||
mFontFeatureSettings = ReactTypefaceUtils.parseFontVariant(fontVariant);
|
||||
}
|
||||
|
||||
/**
|
||||
* /* This code is duplicated in ReactTextInputManager /* TODO: Factor into a common place they
|
||||
* can both use
|
||||
|
||||
@@ -92,6 +92,7 @@ public class TextLayoutManager {
|
||||
new CustomStyleSpan(
|
||||
textAttributes.mFontStyle,
|
||||
textAttributes.mFontWeight,
|
||||
textAttributes.mFontFeatureSettings,
|
||||
textAttributes.mFontFamily,
|
||||
context.getAssets())));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user