Skip to content

Commit b384bb6

Browse files
NickGerlemanfacebook-github-bot
authored andcommitted
Minimize EditText Spans 8/9: CustomStyleSpan (#36577)
Summary: Pull Request resolved: #36577 This is part of a series of changes to minimize the number of spans committed to EditText, as a mitigation for platform issues on Samsung devices. See this [GitHub thread]( #35936 (comment)) for greater context on the platform behavior. This change allows us to strip CustomStyleSpan. We already set all but `fontVariant` on the underlying EditText, so we just need to route that through as well. Note that because this span is non-parcelable, it is seemingly not subject to the buggy behavior on Samsung devices of infinitely cloning the spans, but non-parcelable spans have different issues on the devices (they disappear), so moving `fontVariant` to the top-level makes sense here. Changelog: [Android][Fixed] - Minimize EditText Spans 8/N: CustomStyleSpan Reviewed By: javache Differential Revision: D44297384 fbshipit-source-id: ed4c000e961dd456a2a8f4397e27c23a87defb6e
1 parent 104cb7f commit b384bb6

File tree

3 files changed

+59
-0
lines changed

3 files changed

+59
-0
lines changed

packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/text/CustomStyleSpan.java

+4
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,10 @@ public int getWeight() {
7171
return mFontFamily;
7272
}
7373

74+
public @Nullable String getFontFeatureSettings() {
75+
return mFeatureSettings;
76+
}
77+
7478
private static void apply(
7579
Paint paint,
7680
int style,

packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactEditText.java

+49
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@
6565
import com.facebook.react.views.view.ReactViewBackgroundManager;
6666
import java.util.ArrayList;
6767
import java.util.List;
68+
import java.util.Objects;
6869

6970
/**
7071
* 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) {
518519
}
519520
}
520521

522+
@Override
523+
public void setFontFeatureSettings(String fontFeatureSettings) {
524+
if (!Objects.equals(fontFeatureSettings, getFontFeatureSettings())) {
525+
super.setFontFeatureSettings(fontFeatureSettings);
526+
mTypefaceDirty = true;
527+
}
528+
}
529+
521530
public void maybeUpdateTypeface() {
522531
if (!mTypefaceDirty) {
523532
return;
@@ -529,6 +538,17 @@ public void maybeUpdateTypeface() {
529538
ReactTypefaceUtils.applyStyles(
530539
getTypeface(), mFontStyle, mFontWeight, mFontFamily, getContext().getAssets());
531540
setTypeface(newTypeface);
541+
542+
// Match behavior of CustomStyleSpan and enable SUBPIXEL_TEXT_FLAG when setting anything
543+
// nonstandard
544+
if (mFontStyle != UNSET
545+
|| mFontWeight != UNSET
546+
|| mFontFamily != null
547+
|| getFontFeatureSettings() != null) {
548+
setPaintFlags(getPaintFlags() | Paint.SUBPIXEL_TEXT_FLAG);
549+
} else {
550+
setPaintFlags(getPaintFlags() & (~Paint.SUBPIXEL_TEXT_FLAG));
551+
}
532552
}
533553

534554
// VisibleForTesting from {@link TextInputEventsTestCase}.
@@ -738,6 +758,19 @@ public boolean test(CustomLetterSpacingSpan span) {
738758
}
739759
});
740760
}
761+
762+
stripSpansOfKind(
763+
sb,
764+
CustomStyleSpan.class,
765+
new SpanPredicate<CustomStyleSpan>() {
766+
@Override
767+
public boolean test(CustomStyleSpan span) {
768+
return span.getStyle() == mFontStyle
769+
&& Objects.equals(span.getFontFamily(), mFontFamily)
770+
&& span.getWeight() == mFontWeight
771+
&& Objects.equals(span.getFontFeatureSettings(), getFontFeatureSettings());
772+
}
773+
});
741774
}
742775

743776
private <T> void stripSpansOfKind(
@@ -795,6 +828,22 @@ private void restoreStyleEquivalentSpans(SpannableStringBuilder workingText) {
795828
spanFlags);
796829
}
797830
}
831+
832+
if (mFontStyle != UNSET
833+
|| mFontWeight != UNSET
834+
|| mFontFamily != null
835+
|| getFontFeatureSettings() != null) {
836+
workingText.setSpan(
837+
new CustomStyleSpan(
838+
mFontStyle,
839+
mFontWeight,
840+
getFontFeatureSettings(),
841+
mFontFamily,
842+
getContext().getAssets()),
843+
0,
844+
workingText.length(),
845+
spanFlags);
846+
}
798847
}
799848

800849
private static boolean sameTextForSpan(

packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputManager.java

+6
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@
6969
import com.facebook.react.views.text.ReactBaseTextShadowNode;
7070
import com.facebook.react.views.text.ReactTextUpdate;
7171
import com.facebook.react.views.text.ReactTextViewManagerCallback;
72+
import com.facebook.react.views.text.ReactTypefaceUtils;
7273
import com.facebook.react.views.text.TextAttributeProps;
7374
import com.facebook.react.views.text.TextInlineImageSpan;
7475
import com.facebook.react.views.text.TextLayoutManager;
@@ -413,6 +414,11 @@ public void setFontStyle(ReactEditText view, @Nullable String fontStyle) {
413414
view.setFontStyle(fontStyle);
414415
}
415416

417+
@ReactProp(name = ViewProps.FONT_VARIANT)
418+
public void setFontVariant(ReactEditText view, @Nullable ReadableArray fontVariant) {
419+
view.setFontFeatureSettings(ReactTypefaceUtils.parseFontVariant(fontVariant));
420+
}
421+
416422
@ReactProp(name = ViewProps.INCLUDE_FONT_PADDING, defaultBoolean = true)
417423
public void setIncludeFontPadding(ReactEditText view, boolean includepad) {
418424
view.setIncludeFontPadding(includepad);

0 commit comments

Comments
 (0)