Skip to content

Commit deb7cda

Browse files
NickGerlemankelset
authored andcommittedApr 19, 2023
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 4b9b203 commit deb7cda

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

+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,

‎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
@@ -483,6 +484,14 @@ public void setFontStyle(String fontStyleString) {
483484
}
484485
}
485486

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

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

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

765814
private static boolean sameTextForSpan(

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

+6
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;
@@ -398,6 +399,11 @@ public void setFontStyle(ReactEditText view, @Nullable String fontStyle) {
398399
view.setFontStyle(fontStyle);
399400
}
400401

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

0 commit comments

Comments
 (0)
Please sign in to comment.