Fix controlled TextInput jumbling characters during autocorrect on Fabric#56658
Open
fkgozali wants to merge 1 commit intofacebook:mainfrom
Open
Fix controlled TextInput jumbling characters during autocorrect on Fabric#56658fkgozali wants to merge 1 commit intofacebook:mainfrom
fkgozali wants to merge 1 commit intofacebook:mainfrom
Conversation
…bric
Summary:
On iOS Fabric, a controlled `<TextInput>` could silently drop characters when iOS autocorrect/IME composition was in flight, regressing the controlled-input "jumbled text" behavior that the `TextInput-dynamicWidth-e2e.js` regression test was designed to catch. The test had been left disabled on iOS Fabric configs because of this, masking the real product regression.
Root cause: `RCTTextInputComponentView` snapshots the backing field's `typingAttributes` once at view init time and uses that snapshot as the "insensitive attributes" set for `RCTIsAttributedStringEffectivelySame` — i.e. the set of UIKit-injected attributes the comparison should ignore so it doesn't trigger a destructive `setAttributedText:` on every keystroke. UIKit, however, injects additional typing attributes lazily after the field becomes first responder. Concretely, the init snapshot has `{NSColor, NSParagraphStyle, NSFont}`, but after focus the live `typingAttributes` also contains `NSBackgroundColor` (used for the marked-text highlight during composition/autocorrect) and the React Native event-emitter wrapping key. When iOS performs a multi-step text replacement (e.g. autocorrect substituting `Thos` -> `This`), characters in the backing string transiently carry these extra attributes. The comparison then incorrectly returns "different", we overwrite the backing field mid-replacement, and the in-flight text mutation is corrupted — exactly the original failure mode this code path was meant to prevent.
Fix: introduce `_insensitiveTypingAttributes`, which unions the init snapshot with the live `typingAttributes` at compare time. The init snapshot is preserved as a floor (in case UIKit later removes attributes it had during normal typing), and any attribute UIKit silently injects after focus is now correctly ignored by the comparison.
The fix is small, scoped to `RCTTextInputComponentView.mm`, and preserves the contract of `RCTIsAttributedStringEffectivelySame`: we only broaden the insensitive set, never narrow it.
Changelog:
[iOS][Fixed] - Fix controlled TextInput jumbling characters during autocorrect/IME composition on Fabric
Differential Revision: D103123618
|
@fkgozali has exported this pull request. If you are a Meta employee, you can view the originating Diff in D103123618. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary:
On iOS Fabric, a controlled
<TextInput>could silently drop characters when iOS autocorrect/IME composition was in flight, regressing the controlled-input "jumbled text" behavior that theTextInput-dynamicWidth-e2e.jsregression test was designed to catch. The test had been left disabled on iOS Fabric configs because of this, masking the real product regression.Root cause:
RCTTextInputComponentViewsnapshots the backing field'stypingAttributesonce at view init time and uses that snapshot as the "insensitive attributes" set forRCTIsAttributedStringEffectivelySame— i.e. the set of UIKit-injected attributes the comparison should ignore so it doesn't trigger a destructivesetAttributedText:on every keystroke. UIKit, however, injects additional typing attributes lazily after the field becomes first responder. Concretely, the init snapshot has{NSColor, NSParagraphStyle, NSFont}, but after focus the livetypingAttributesalso containsNSBackgroundColor(used for the marked-text highlight during composition/autocorrect) and the React Native event-emitter wrapping key. When iOS performs a multi-step text replacement (e.g. autocorrect substitutingThos->This), characters in the backing string transiently carry these extra attributes. The comparison then incorrectly returns "different", we overwrite the backing field mid-replacement, and the in-flight text mutation is corrupted — exactly the original failure mode this code path was meant to prevent.Fix: introduce
_insensitiveTypingAttributes, which unions the init snapshot with the livetypingAttributesat compare time. The init snapshot is preserved as a floor (in case UIKit later removes attributes it had during normal typing), and any attribute UIKit silently injects after focus is now correctly ignored by the comparison.The fix is small, scoped to
RCTTextInputComponentView.mm, and preserves the contract ofRCTIsAttributedStringEffectivelySame: we only broaden the insensitive set, never narrow it.Changelog:
[iOS][Fixed] - Fix controlled TextInput jumbling characters during autocorrect/IME composition on Fabric
Differential Revision: D103123618