Skip to content

Commit ee2d815

Browse files
NickGerlemankelset
authored andcommittedApr 19, 2023
Minimize EditText Spans 1/9: Fix precedence (#36543)
Summary: Pull Request resolved: #36543 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. We cache the backing EditText span on text change to later measure. To measure outside of a TextInput we need to restore any spans we removed. Spans may overlap, so base attributes should be behind everything else. The logic here for dealing with precedence is incorrect, and we should instead accomplish this by twiddling with the `SPAN_PRIORITY` bits. Changelog: [Android][Fixed] - Minimize Spans 1/N: Fix precedence Reviewed By: javache Differential Revision: D44240779 fbshipit-source-id: f731b353587888faad946b8cf1e868095cdeced3
1 parent 0bcf293 commit ee2d815

File tree

1 file changed

+8
-19
lines changed

1 file changed

+8
-19
lines changed
 

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

+8-19
Original file line numberDiff line numberDiff line change
@@ -648,29 +648,18 @@ private void stripAtributeEquivalentSpans(SpannableStringBuilder sb) {
648648
}
649649
}
650650

651-
private void unstripAttributeEquivalentSpans(
652-
SpannableStringBuilder workingText, Spannable originalText) {
653-
// We must add spans back for Fabric to be able to measure, at lower precedence than any
654-
// existing spans. Remove all spans, add the attributes, then re-add the spans over
655-
workingText.append(originalText);
651+
private void unstripAttributeEquivalentSpans(SpannableStringBuilder workingText) {
652+
int spanFlags = Spannable.SPAN_INCLUSIVE_INCLUSIVE;
656653

657-
for (Object span : workingText.getSpans(0, workingText.length(), Object.class)) {
658-
workingText.removeSpan(span);
659-
}
654+
// Set all bits for SPAN_PRIORITY so that this span has the highest possible priority
655+
// (least precedence). This ensures the span is behind any overlapping spans.
656+
spanFlags |= Spannable.SPAN_PRIORITY;
660657

661658
workingText.setSpan(
662659
new ReactAbsoluteSizeSpan(mTextAttributes.getEffectiveFontSize()),
663660
0,
664661
workingText.length(),
665-
Spanned.SPAN_INCLUSIVE_INCLUSIVE);
666-
667-
for (Object span : originalText.getSpans(0, originalText.length(), Object.class)) {
668-
workingText.setSpan(
669-
span,
670-
originalText.getSpanStart(span),
671-
originalText.getSpanEnd(span),
672-
originalText.getSpanFlags(span));
673-
}
662+
spanFlags);
674663
}
675664

676665
private static boolean sameTextForSpan(
@@ -1091,8 +1080,8 @@ private void updateCachedSpannable(boolean resetStyles) {
10911080
// ...
10921081
// - android.app.Activity.dispatchKeyEvent (Activity.java:3447)
10931082
try {
1094-
Spannable text = (Spannable) currentText.subSequence(0, currentText.length());
1095-
unstripAttributeEquivalentSpans(sb, text);
1083+
sb.append(currentText.subSequence(0, currentText.length()));
1084+
unstripAttributeEquivalentSpans(sb);
10961085
} catch (IndexOutOfBoundsException e) {
10971086
ReactSoftExceptionLogger.logSoftException(TAG, e);
10981087
}

0 commit comments

Comments
 (0)
Please sign in to comment.