diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/text/CustomStyleSpan.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/text/CustomStyleSpan.java index b249126cf95750..7866390bfa09bd 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/text/CustomStyleSpan.java +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/text/CustomStyleSpan.java @@ -71,6 +71,10 @@ public int getWeight() { return mFontFamily; } + public @Nullable String getFontFeatureSettings() { + return mFeatureSettings; + } + private static void apply( Paint paint, int style, diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactEditText.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactEditText.java index a1b10ae1a4af7f..0c6f9c4c625fe7 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactEditText.java +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactEditText.java @@ -65,6 +65,7 @@ import com.facebook.react.views.view.ReactViewBackgroundManager; import java.util.ArrayList; import java.util.List; +import java.util.Objects; /** * A wrapper around the EditText that lets us better control what happens when an EditText gets @@ -518,6 +519,14 @@ public void setFontStyle(String fontStyleString) { } } + @Override + public void setFontFeatureSettings(String fontFeatureSettings) { + if (!Objects.equals(fontFeatureSettings, getFontFeatureSettings())) { + super.setFontFeatureSettings(fontFeatureSettings); + mTypefaceDirty = true; + } + } + public void maybeUpdateTypeface() { if (!mTypefaceDirty) { return; @@ -529,6 +538,17 @@ public void maybeUpdateTypeface() { ReactTypefaceUtils.applyStyles( getTypeface(), mFontStyle, mFontWeight, mFontFamily, getContext().getAssets()); setTypeface(newTypeface); + + // Match behavior of CustomStyleSpan and enable SUBPIXEL_TEXT_FLAG when setting anything + // nonstandard + if (mFontStyle != UNSET + || mFontWeight != UNSET + || mFontFamily != null + || getFontFeatureSettings() != null) { + setPaintFlags(getPaintFlags() | Paint.SUBPIXEL_TEXT_FLAG); + } else { + setPaintFlags(getPaintFlags() & (~Paint.SUBPIXEL_TEXT_FLAG)); + } } // VisibleForTesting from {@link TextInputEventsTestCase}. @@ -738,6 +758,19 @@ public boolean test(CustomLetterSpacingSpan span) { } }); } + + stripSpansOfKind( + sb, + CustomStyleSpan.class, + new SpanPredicate() { + @Override + public boolean test(CustomStyleSpan span) { + return span.getStyle() == mFontStyle + && Objects.equals(span.getFontFamily(), mFontFamily) + && span.getWeight() == mFontWeight + && Objects.equals(span.getFontFeatureSettings(), getFontFeatureSettings()); + } + }); } private void stripSpansOfKind( @@ -795,6 +828,22 @@ private void restoreStyleEquivalentSpans(SpannableStringBuilder workingText) { spanFlags); } } + + if (mFontStyle != UNSET + || mFontWeight != UNSET + || mFontFamily != null + || getFontFeatureSettings() != null) { + workingText.setSpan( + new CustomStyleSpan( + mFontStyle, + mFontWeight, + getFontFeatureSettings(), + mFontFamily, + getContext().getAssets()), + 0, + workingText.length(), + spanFlags); + } } private static boolean sameTextForSpan( diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputManager.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputManager.java index 82ca31fc247150..eb5927429c65e6 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputManager.java +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputManager.java @@ -69,6 +69,7 @@ import com.facebook.react.views.text.ReactBaseTextShadowNode; import com.facebook.react.views.text.ReactTextUpdate; import com.facebook.react.views.text.ReactTextViewManagerCallback; +import com.facebook.react.views.text.ReactTypefaceUtils; import com.facebook.react.views.text.TextAttributeProps; import com.facebook.react.views.text.TextInlineImageSpan; import com.facebook.react.views.text.TextLayoutManager; @@ -413,6 +414,11 @@ public void setFontStyle(ReactEditText view, @Nullable String fontStyle) { view.setFontStyle(fontStyle); } + @ReactProp(name = ViewProps.FONT_VARIANT) + public void setFontVariant(ReactEditText view, @Nullable ReadableArray fontVariant) { + view.setFontFeatureSettings(ReactTypefaceUtils.parseFontVariant(fontVariant)); + } + @ReactProp(name = ViewProps.INCLUDE_FONT_PADDING, defaultBoolean = true) public void setIncludeFontPadding(ReactEditText view, boolean includepad) { view.setIncludeFontPadding(includepad);