diff --git a/Libraries/DeprecatedPropTypes/DeprecatedTextStylePropTypes.js b/Libraries/DeprecatedPropTypes/DeprecatedTextStylePropTypes.js
index 63ab3213ffd6e7..428b2d38aab2e3 100644
--- a/Libraries/DeprecatedPropTypes/DeprecatedTextStylePropTypes.js
+++ b/Libraries/DeprecatedPropTypes/DeprecatedTextStylePropTypes.js
@@ -54,9 +54,6 @@ const DeprecatedTextStylePropTypes = {
| '800'
| '900',
>),
- /**
- * @platform ios
- */
fontVariant: (ReactPropTypes.arrayOf(
ReactPropTypes.oneOf([
'small-caps',
diff --git a/RNTester/js/examples/Text/TextExample.android.js b/RNTester/js/examples/Text/TextExample.android.js
index ae3aa5c81179da..fc4a241ee23cdc 100644
--- a/RNTester/js/examples/Text/TextExample.android.js
+++ b/RNTester/js/examples/Text/TextExample.android.js
@@ -574,6 +574,33 @@ class TextExample extends React.Component<{}> {
This very long text should be clipped and this will not be visible.
+
+ Small Caps{'\n'}
+
+ Old Style nums 0123456789{'\n'}
+
+
+ Lining nums 0123456789{'\n'}
+
+
+ Tabular nums{'\n'}
+ 1111{'\n'}
+ 2222{'\n'}
+
+
+ Proportional nums{'\n'}
+ 1111{'\n'}
+ 2222{'\n'}
+
+
= Build.VERSION_CODES.LOLLIPOP) {
+ paint.setFontFeatureSettings(fontFeatureSettings);
+ }
paint.setTypeface(typeface);
paint.setSubpixelText(true);
}
diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactBaseTextShadowNode.java b/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactBaseTextShadowNode.java
index 717aec41e9628b..76c658212edd15 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactBaseTextShadowNode.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactBaseTextShadowNode.java
@@ -18,6 +18,7 @@
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.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 @@ private static void buildSpannedFromShadowNode(
new CustomStyleSpan(
textShadowNode.mFontStyle,
textShadowNode.mFontWeight,
+ textShadowNode.mFontFeatureSettings,
textShadowNode.mFontFamily,
textShadowNode.getThemedContext().getAssets())));
}
@@ -357,6 +360,11 @@ protected Spannable spannedFromShadowNode(
*/
protected @Nullable String mFontFamily = null;
+ /**
+ * @see android.graphics.Paint#setFontFeatureSettings
+ */
+ protected @Nullable String mFontFeatureSettings = null;
+
protected boolean mContainsImages = false;
protected Map mInlineViews;
@@ -483,6 +491,16 @@ public void setFontWeight(@Nullable String fontWeightString) {
}
}
+ @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);
diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactTypefaceUtils.java b/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactTypefaceUtils.java
index 7910deadf6e162..c811e2f757cd8c 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactTypefaceUtils.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactTypefaceUtils.java
@@ -13,6 +13,11 @@
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 static int parseFontStyle(@Nullable String fontStyleString) {
return fontStyle;
}
+ public static @Nullable String parseFontVariant(@Nullable ReadableArray fontVariantArray) {
+ if (fontVariantArray == null || fontVariantArray.size() == 0) {
+ return null;
+ }
+
+ List 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;
diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/text/TextAttributeProps.java b/ReactAndroid/src/main/java/com/facebook/react/views/text/TextAttributeProps.java
index a0bf03f1413c8e..ca26c4f7a6d723 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/views/text/TextAttributeProps.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/text/TextAttributeProps.java
@@ -13,6 +13,7 @@
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 TextAttributeProps(ReactStylesDiffMap props) {
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 @@ private float getFloatProp(String name, float defaultvalue) {
}
}
+ 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 void setFontFamily(@Nullable String fontFamily) {
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
diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/text/TextLayoutManager.java b/ReactAndroid/src/main/java/com/facebook/react/views/text/TextLayoutManager.java
index 995856c7102ba0..25697da7b594c6 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/views/text/TextLayoutManager.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/text/TextLayoutManager.java
@@ -92,6 +92,7 @@ private static void buildSpannableFromFragment(
new CustomStyleSpan(
textAttributes.mFontStyle,
textAttributes.mFontWeight,
+ textAttributes.mFontFeatureSettings,
textAttributes.mFontFamily,
context.getAssets())));
}