Skip to content

Commit e89f919

Browse files
NickGerlemankelset
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 3b07e7e commit e89f919

File tree

3 files changed

+59
-0
lines changed

3 files changed

+59
-0
lines changed

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

Lines changed: 4 additions & 0 deletions
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,

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

Lines changed: 49 additions & 0 deletions
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
@@ -482,6 +483,14 @@ public void setFontStyle(String fontStyleString) {
482483
}
483484
}
484485

486+
@Override
487+
public void setFontFeatureSettings(String fontFeatureSettings) {
488+
if (!Objects.equals(fontFeatureSettings, getFontFeatureSettings())) {
489+
super.setFontFeatureSettings(fontFeatureSettings);
490+
mTypefaceDirty = true;
491+
}
492+
}
493+
485494
public void maybeUpdateTypeface() {
486495
if (!mTypefaceDirty) {
487496
return;
@@ -493,6 +502,17 @@ public void maybeUpdateTypeface() {
493502
ReactTypefaceUtils.applyStyles(
494503
getTypeface(), mFontStyle, mFontWeight, mFontFamily, getContext().getAssets());
495504
setTypeface(newTypeface);
505+
506+
// Match behavior of CustomStyleSpan and enable SUBPIXEL_TEXT_FLAG when setting anything
507+
// nonstandard
508+
if (mFontStyle != UNSET
509+
|| mFontWeight != UNSET
510+
|| mFontFamily != null
511+
|| getFontFeatureSettings() != null) {
512+
setPaintFlags(getPaintFlags() | Paint.SUBPIXEL_TEXT_FLAG);
513+
} else {
514+
setPaintFlags(getPaintFlags() & (~Paint.SUBPIXEL_TEXT_FLAG));
515+
}
496516
}
497517

498518
// VisibleForTesting from {@link TextInputEventsTestCase}.
@@ -702,6 +722,19 @@ public boolean test(CustomLetterSpacingSpan span) {
702722
}
703723
});
704724
}
725+
726+
stripSpansOfKind(
727+
sb,
728+
CustomStyleSpan.class,
729+
new SpanPredicate<CustomStyleSpan>() {
730+
@Override
731+
public boolean test(CustomStyleSpan span) {
732+
return span.getStyle() == mFontStyle
733+
&& Objects.equals(span.getFontFamily(), mFontFamily)
734+
&& span.getWeight() == mFontWeight
735+
&& Objects.equals(span.getFontFeatureSettings(), getFontFeatureSettings());
736+
}
737+
});
705738
}
706739

707740
private <T> void stripSpansOfKind(
@@ -759,6 +792,22 @@ private void restoreStyleEquivalentSpans(SpannableStringBuilder workingText) {
759792
spanFlags);
760793
}
761794
}
795+
796+
if (mFontStyle != UNSET
797+
|| mFontWeight != UNSET
798+
|| mFontFamily != null
799+
|| getFontFeatureSettings() != null) {
800+
workingText.setSpan(
801+
new CustomStyleSpan(
802+
mFontStyle,
803+
mFontWeight,
804+
getFontFeatureSettings(),
805+
mFontFamily,
806+
getContext().getAssets()),
807+
0,
808+
workingText.length(),
809+
spanFlags);
810+
}
762811
}
763812

764813
private static boolean sameTextForSpan(

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

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@
6868
import com.facebook.react.views.text.ReactBaseTextShadowNode;
6969
import com.facebook.react.views.text.ReactTextUpdate;
7070
import com.facebook.react.views.text.ReactTextViewManagerCallback;
71+
import com.facebook.react.views.text.ReactTypefaceUtils;
7172
import com.facebook.react.views.text.TextAttributeProps;
7273
import com.facebook.react.views.text.TextInlineImageSpan;
7374
import com.facebook.react.views.text.TextLayoutManager;
@@ -397,6 +398,11 @@ public void setFontStyle(ReactEditText view, @Nullable String fontStyle) {
397398
view.setFontStyle(fontStyle);
398399
}
399400

401+
@ReactProp(name = ViewProps.FONT_VARIANT)
402+
public void setFontVariant(ReactEditText view, @Nullable ReadableArray fontVariant) {
403+
view.setFontFeatureSettings(ReactTypefaceUtils.parseFontVariant(fontVariant));
404+
}
405+
400406
@ReactProp(name = ViewProps.INCLUDE_FONT_PADDING, defaultBoolean = true)
401407
public void setIncludeFontPadding(ReactEditText view, boolean includepad) {
402408
view.setIncludeFontPadding(includepad);

0 commit comments

Comments
 (0)