Skip to content

Commit ec39c46

Browse files
NickGerlemanfacebook-github-bot
authored andcommitted
Minimize Spans 1/N: Fix precedence
Summary: 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 Differential Revision: https://internalfb.com/D44240779 fbshipit-source-id: 57509464f0b07a9472f3098cae6b486038f0c7c3
1 parent 6956d4f commit ec39c46

File tree

1 file changed

+8
-19
lines changed
  • packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/textinput

1 file changed

+8
-19
lines changed

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

Lines changed: 8 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -683,29 +683,18 @@ private void stripAttributeEquivalentSpans(SpannableStringBuilder sb) {
683683
}
684684
}
685685

686-
private void unstripAttributeEquivalentSpans(
687-
SpannableStringBuilder workingText, Spannable originalText) {
688-
// We must add spans back for Fabric to be able to measure, at lower precedence than any
689-
// existing spans. Remove all spans, add the attributes, then re-add the spans over
690-
workingText.append(originalText);
686+
private void unstripAttributeEquivalentSpans(SpannableStringBuilder workingText) {
687+
int spanFlags = Spannable.SPAN_INCLUSIVE_INCLUSIVE;
691688

692-
for (Object span : workingText.getSpans(0, workingText.length(), Object.class)) {
693-
workingText.removeSpan(span);
694-
}
689+
// Set all bits for SPAN_PRIORITY so that this span has the highest possible priority
690+
// (least precedence). This ensures the span is behind any overlapping spans.
691+
spanFlags |= Spannable.SPAN_PRIORITY;
695692

696693
workingText.setSpan(
697694
new ReactAbsoluteSizeSpan(mTextAttributes.getEffectiveFontSize()),
698695
0,
699696
workingText.length(),
700-
Spanned.SPAN_INCLUSIVE_INCLUSIVE);
701-
702-
for (Object span : originalText.getSpans(0, originalText.length(), Object.class)) {
703-
workingText.setSpan(
704-
span,
705-
originalText.getSpanStart(span),
706-
originalText.getSpanEnd(span),
707-
originalText.getSpanFlags(span));
708-
}
697+
spanFlags);
709698
}
710699

711700
private static boolean sameTextForSpan(
@@ -1132,8 +1121,8 @@ private void updateCachedSpannable(boolean resetStyles) {
11321121
// ...
11331122
// - android.app.Activity.dispatchKeyEvent (Activity.java:3447)
11341123
try {
1135-
Spannable text = (Spannable) currentText.subSequence(0, currentText.length());
1136-
unstripAttributeEquivalentSpans(sb, text);
1124+
sb.append(currentText.subSequence(0, currentText.length()));
1125+
unstripAttributeEquivalentSpans(sb);
11371126
} catch (IndexOutOfBoundsException e) {
11381127
ReactSoftExceptionLogger.logSoftException(TAG, e);
11391128
}

0 commit comments

Comments
 (0)