6464import com .facebook .react .views .text .TextLayoutManager ;
6565import com .facebook .react .views .view .ReactViewBackgroundManager ;
6666import java .util .ArrayList ;
67- import java .util .List ;
6867
6968/**
7069 * A wrapper around the EditText that lets us better control what happens when an EditText gets
@@ -88,7 +87,6 @@ public class ReactEditText extends AppCompatEditText
8887 // *TextChanged events should be triggered. This is less expensive than removing the text
8988 // listeners and adding them back again after the text change is completed.
9089 protected boolean mIsSettingTextFromJS ;
91- protected boolean mIsSettingTextFromCacheUpdate = false ;
9290 private int mDefaultGravityHorizontal ;
9391 private int mDefaultGravityVertical ;
9492
@@ -368,7 +366,7 @@ protected void onSelectionChanged(int selStart, int selEnd) {
368366 }
369367
370368 super .onSelectionChanged (selStart , selEnd );
371- if (! mIsSettingTextFromCacheUpdate && mSelectionWatcher != null && hasFocus ()) {
369+ if (mSelectionWatcher != null && hasFocus ()) {
372370 mSelectionWatcher .onSelectionChanged (selStart , selEnd );
373371 }
374372 }
@@ -610,7 +608,7 @@ public void maybeSetText(ReactTextUpdate reactTextUpdate) {
610608 SpannableStringBuilder spannableStringBuilder =
611609 new SpannableStringBuilder (reactTextUpdate .getText ());
612610
613- manageSpans (spannableStringBuilder , reactTextUpdate . mContainsMultipleFragments );
611+ manageSpans (spannableStringBuilder );
614612 stripStyleEquivalentSpans (spannableStringBuilder );
615613
616614 mContainsImages = reactTextUpdate .containsImages ();
@@ -639,7 +637,7 @@ public void maybeSetText(ReactTextUpdate reactTextUpdate) {
639637 }
640638
641639 // Update cached spans (in Fabric only).
642- updateCachedSpannable (false );
640+ updateCachedSpannable ();
643641 }
644642
645643 /**
@@ -648,8 +646,7 @@ public void maybeSetText(ReactTextUpdate reactTextUpdate) {
648646 * will adapt to the new text, hence why {@link SpannableStringBuilder#replace} never removes
649647 * them.
650648 */
651- private void manageSpans (
652- SpannableStringBuilder spannableStringBuilder , boolean skipAddSpansForMeasurements ) {
649+ private void manageSpans (SpannableStringBuilder spannableStringBuilder ) {
653650 Object [] spans = getText ().getSpans (0 , length (), Object .class );
654651 for (int spanIdx = 0 ; spanIdx < spans .length ; spanIdx ++) {
655652 Object span = spans [spanIdx ];
@@ -677,13 +674,6 @@ private void manageSpans(
677674 spannableStringBuilder .setSpan (span , spanStart , spanEnd , spanFlags );
678675 }
679676 }
680-
681- // In Fabric only, apply necessary styles to entire span
682- // If the Spannable was constructed from multiple fragments, we don't apply any spans that could
683- // impact the whole Spannable, because that would override "local" styles per-fragment
684- if (!skipAddSpansForMeasurements ) {
685- addSpansForMeasurement (getText ());
686- }
687677 }
688678
689679 // TODO: Replace with Predicate<T> and lambdas once Java 8 builds in OSS
@@ -800,10 +790,10 @@ private <T> void stripSpansOfKind(
800790 }
801791
802792 /**
803- * Copy back styles represented as attributes to the underlying span, for later measurement
804- * outside the ReactEditText.
793+ * Copy styles represented as attributes to the underlying span, for later measurement or other
794+ * usage outside the ReactEditText.
805795 */
806- private void restoreStyleEquivalentSpans (SpannableStringBuilder workingText ) {
796+ private void addSpansFromStyleAttributes (SpannableStringBuilder workingText ) {
807797 int spanFlags = Spannable .SPAN_INCLUSIVE_INCLUSIVE ;
808798
809799 // Set all bits for SPAN_PRIORITY so that this span has the highest possible priority
@@ -859,6 +849,11 @@ private void restoreStyleEquivalentSpans(SpannableStringBuilder workingText) {
859849 workingText .length (),
860850 spanFlags );
861851 }
852+
853+ float lineHeight = mTextAttributes .getEffectiveLineHeight ();
854+ if (!Float .isNaN (lineHeight )) {
855+ workingText .setSpan (new CustomLineHeightSpan (lineHeight ), 0 , workingText .length (), spanFlags );
856+ }
862857 }
863858
864859 private static boolean sameTextForSpan (
@@ -877,73 +872,6 @@ private static boolean sameTextForSpan(
877872 return true ;
878873 }
879874
880- // This is hacked in for Fabric. When we delete non-Fabric code, we might be able to simplify or
881- // clean this up a bit.
882- private void addSpansForMeasurement (Spannable spannable ) {
883- if (!mFabricViewStateManager .hasStateWrapper ()) {
884- return ;
885- }
886-
887- boolean originalDisableTextDiffing = mDisableTextDiffing ;
888- mDisableTextDiffing = true ;
889-
890- int start = 0 ;
891- int end = spannable .length ();
892-
893- // Remove duplicate spans we might add here
894- Object [] spans = spannable .getSpans (0 , length (), Object .class );
895- for (Object span : spans ) {
896- int spanFlags = spannable .getSpanFlags (span );
897- boolean isInclusive =
898- (spanFlags & Spanned .SPAN_INCLUSIVE_INCLUSIVE ) == Spanned .SPAN_INCLUSIVE_INCLUSIVE
899- || (spanFlags & Spanned .SPAN_INCLUSIVE_EXCLUSIVE ) == Spanned .SPAN_INCLUSIVE_EXCLUSIVE ;
900- if (isInclusive
901- && span instanceof ReactSpan
902- && spannable .getSpanStart (span ) == start
903- && spannable .getSpanEnd (span ) == end ) {
904- spannable .removeSpan (span );
905- }
906- }
907-
908- List <TextLayoutManager .SetSpanOperation > ops = new ArrayList <>();
909-
910- if (!Float .isNaN (mTextAttributes .getLetterSpacing ())) {
911- ops .add (
912- new TextLayoutManager .SetSpanOperation (
913- start , end , new CustomLetterSpacingSpan (mTextAttributes .getLetterSpacing ())));
914- }
915- ops .add (
916- new TextLayoutManager .SetSpanOperation (
917- start , end , new ReactAbsoluteSizeSpan ((int ) mTextAttributes .getEffectiveFontSize ())));
918- if (mFontStyle != UNSET || mFontWeight != UNSET || mFontFamily != null ) {
919- ops .add (
920- new TextLayoutManager .SetSpanOperation (
921- start ,
922- end ,
923- new CustomStyleSpan (
924- mFontStyle ,
925- mFontWeight ,
926- null , // TODO: do we need to support FontFeatureSettings / fontVariant?
927- mFontFamily ,
928- getReactContext (ReactEditText .this ).getAssets ())));
929- }
930- if (!Float .isNaN (mTextAttributes .getEffectiveLineHeight ())) {
931- ops .add (
932- new TextLayoutManager .SetSpanOperation (
933- start , end , new CustomLineHeightSpan (mTextAttributes .getEffectiveLineHeight ())));
934- }
935-
936- int priority = 0 ;
937- for (TextLayoutManager .SetSpanOperation op : ops ) {
938- // Actual order of calling {@code execute} does NOT matter,
939- // but the {@code priority} DOES matter.
940- op .execute (spannable , priority );
941- priority ++;
942- }
943-
944- mDisableTextDiffing = originalDisableTextDiffing ;
945- }
946-
947875 protected boolean showSoftKeyboard () {
948876 return mInputMethodManager .showSoftInput (this , 0 );
949877 }
@@ -1230,7 +1158,7 @@ public FabricViewStateManager getFabricViewStateManager() {
12301158 * TextLayoutManager.java with some very minor modifications. There's some duplication between
12311159 * here and TextLayoutManager, so there might be an opportunity for refactor.
12321160 */
1233- private void updateCachedSpannable (boolean resetStyles ) {
1161+ private void updateCachedSpannable () {
12341162 // Noops in non-Fabric
12351163 if (mFabricViewStateManager == null || !mFabricViewStateManager .hasStateWrapper ()) {
12361164 return ;
@@ -1240,12 +1168,6 @@ private void updateCachedSpannable(boolean resetStyles) {
12401168 return ;
12411169 }
12421170
1243- if (resetStyles ) {
1244- mIsSettingTextFromCacheUpdate = true ;
1245- addSpansForMeasurement (getText ());
1246- mIsSettingTextFromCacheUpdate = false ;
1247- }
1248-
12491171 Editable currentText = getText ();
12501172 boolean haveText = currentText != null && currentText .length () > 0 ;
12511173
@@ -1288,7 +1210,6 @@ private void updateCachedSpannable(boolean resetStyles) {
12881210 // - android.app.Activity.dispatchKeyEvent (Activity.java:3447)
12891211 try {
12901212 sb .append (currentText .subSequence (0 , currentText .length ()));
1291- restoreStyleEquivalentSpans (sb );
12921213 } catch (IndexOutOfBoundsException e ) {
12931214 ReactSoftExceptionLogger .logSoftException (TAG , e );
12941215 }
@@ -1304,11 +1225,9 @@ private void updateCachedSpannable(boolean resetStyles) {
13041225 // Measure something so we have correct height, even if there's no string.
13051226 sb .append ("I" );
13061227 }
1307-
1308- // Make sure that all text styles are applied when we're measurable the hint or "blank" text
1309- addSpansForMeasurement (sb );
13101228 }
13111229
1230+ addSpansFromStyleAttributes (sb );
13121231 TextLayoutManager .setCachedSpannabledForTag (getId (), sb );
13131232 }
13141233
@@ -1323,7 +1242,7 @@ void setEventDispatcher(@Nullable EventDispatcher eventDispatcher) {
13231242 private class TextWatcherDelegator implements TextWatcher {
13241243 @ Override
13251244 public void beforeTextChanged (CharSequence s , int start , int count , int after ) {
1326- if (!mIsSettingTextFromCacheUpdate && ! mIsSettingTextFromJS && mListeners != null ) {
1245+ if (!mIsSettingTextFromJS && mListeners != null ) {
13271246 for (TextWatcher listener : mListeners ) {
13281247 listener .beforeTextChanged (s , start , count , after );
13291248 }
@@ -1337,23 +1256,20 @@ public void onTextChanged(CharSequence s, int start, int before, int count) {
13371256 TAG , "onTextChanged[" + getId () + "]: " + s + " " + start + " " + before + " " + count );
13381257 }
13391258
1340- if (!mIsSettingTextFromCacheUpdate ) {
1341- if (!mIsSettingTextFromJS && mListeners != null ) {
1342- for (TextWatcher listener : mListeners ) {
1343- listener .onTextChanged (s , start , before , count );
1344- }
1259+ if (!mIsSettingTextFromJS && mListeners != null ) {
1260+ for (TextWatcher listener : mListeners ) {
1261+ listener .onTextChanged (s , start , before , count );
13451262 }
1346-
1347- updateCachedSpannable (
1348- !mIsSettingTextFromJS && !mIsSettingTextFromState && start == 0 && before == 0 );
13491263 }
13501264
1265+ updateCachedSpannable ();
1266+
13511267 onContentSizeChange ();
13521268 }
13531269
13541270 @ Override
13551271 public void afterTextChanged (Editable s ) {
1356- if (!mIsSettingTextFromCacheUpdate && ! mIsSettingTextFromJS && mListeners != null ) {
1272+ if (!mIsSettingTextFromJS && mListeners != null ) {
13571273 for (TextWatcher listener : mListeners ) {
13581274 listener .afterTextChanged (s );
13591275 }
0 commit comments