Files
orca/mobile/patches/react-native@0.83.10.patch
T
Kelvin Amoaba ef3d9bbdc2 perf(mobile): seal and decode socket frames through native bindings (#39053)
* perf(mobile): seal and decode socket frames through native bindings

* refactor(mobile): decode base64 socket messages with the canonical primitive

* refactor(mobile): share the canonical base64 decoder with socket payloads
2026-11-06 18:11:41 +00:00

146 lines
6.5 KiB
Diff

diff --git a/React/Fabric/Mounting/ComponentViews/TextInput/RCTTextInputComponentView.mm b/React/Fabric/Mounting/ComponentViews/TextInput/RCTTextInputComponentView.mm
index d02e003a439e410ddab597b2c036256c80db0395..cf745cf37a37d34f9e93eb8df10b43cb54ab91a3 100644
--- a/React/Fabric/Mounting/ComponentViews/TextInput/RCTTextInputComponentView.mm
+++ b/React/Fabric/Mounting/ComponentViews/TextInput/RCTTextInputComponentView.mm
@@ -382,6 +382,7 @@
_backedTextInputView.inputAccessoryView = nil;
_hasInputAccessoryView = false;
[_backedTextInputView resignFirstResponder];
+ [_backedTextInputView resetDictationRecognition];
}
#pragma mark - RCTBackedTextInputDelegate
@@ -703,6 +704,7 @@ static NSSet<NSNumber *> *returnKeyTypesSet;
{
return {
.text = RCTStringFromNSString(_backedTextInputView.attributedText.string),
+ .isComposing = _backedTextInputView.markedTextRange != nil,
.selectionRange = [self _selectionRange],
.eventCount = static_cast<int>(_mostRecentEventCount),
.contentOffset = RCTPointFromCGPoint(_backedTextInputView.contentOffset),
@@ -865,4 +867,6 @@ static NSSet<NSNumber *> *returnKeyTypesSet;
+ // Preserve the native recognition placeholder while iOS finalizes dictation.
BOOL shouldFallbackToBareTextComparison =
[_backedTextInputView.textInputMode.primaryLanguage isEqualToString:@"dictation"] ||
+ _backedTextInputView.dictationRecognizing ||
[_backedTextInputView.textInputMode.primaryLanguage isEqualToString:@"ko-KR"] ||
_backedTextInputView.markedTextRange || _backedTextInputView.isSecureTextEntry || fontHasBeenUpdatedBySystem;
diff --git a/ReactCommon/react/renderer/components/textinput/TextInputEventEmitter.cpp b/ReactCommon/react/renderer/components/textinput/TextInputEventEmitter.cpp
index a9bc219f8bf729111e907423ca61b991fd712b46..60e9c6f54edb295295d6e48d1d554499106b7e57 100644
--- a/ReactCommon/react/renderer/components/textinput/TextInputEventEmitter.cpp
+++ b/ReactCommon/react/renderer/components/textinput/TextInputEventEmitter.cpp
@@ -24,6 +24,10 @@ static jsi::Value textInputMetricsPayload(
payload.setProperty(runtime, "eventCount", textInputMetrics.eventCount);
+ if (textInputMetrics.isComposing.has_value()) {
+ payload.setProperty(runtime, "isComposing", *textInputMetrics.isComposing);
+ }
+
if (includeSelectionState) {
auto selection = jsi::Object(runtime);
selection.setProperty(
diff --git a/ReactCommon/react/renderer/components/textinput/TextInputEventEmitter.h b/ReactCommon/react/renderer/components/textinput/TextInputEventEmitter.h
index a3f2e01c130c1a53aee0b39e72927d21f2a6973d..c9d34f8b42644800b5c85e5be45b6ebfbe94a54d 100644
--- a/ReactCommon/react/renderer/components/textinput/TextInputEventEmitter.h
+++ b/ReactCommon/react/renderer/components/textinput/TextInputEventEmitter.h
@@ -7,6 +7,8 @@
#pragma once
+#include <optional>
+
#include <react/renderer/attributedstring/AttributedString.h>
#include <react/renderer/components/view/ViewEventEmitter.h>
@@ -18,6 +20,7 @@ class TextInputEventEmitter : public ViewEventEmitter {
struct Metrics {
std::string text;
+ std::optional<bool> isComposing;
AttributedString::Range selectionRange;
// ScrollView-like metrics
Size contentSize;
diff --git a/React/Fabric/Mounting/ComponentViews/Text/RCTParagraphComponentView.mm b/React/Fabric/Mounting/ComponentViews/Text/RCTParagraphComponentView.mm
index 79ee7ffe43..956f189a1c 100644
--- a/React/Fabric/Mounting/ComponentViews/Text/RCTParagraphComponentView.mm
+++ b/React/Fabric/Mounting/ComponentViews/Text/RCTParagraphComponentView.mm
@@ -136,6 +136,7 @@ using namespace facebook::react;
- (void)prepareForRecycle
{
[super prepareForRecycle];
_textView.state = nullptr;
+ _textView.layoutMetrics = EmptyLayoutMetrics;
_accessibilityProvider = nil;
}
diff --git a/Libraries/Text/TextInput/RCTBackedTextInputViewProtocol.h b/Libraries/Text/TextInput/RCTBackedTextInputViewProtocol.h
--- a/Libraries/Text/TextInput/RCTBackedTextInputViewProtocol.h
+++ b/Libraries/Text/TextInput/RCTBackedTextInputViewProtocol.h
@@ -48,6 +48,7 @@
- (void)setSelectedTextRange:(nullable UITextRange *)selectedTextRange NS_UNAVAILABLE;
- (void)setSelectedTextRange:(nullable UITextRange *)selectedTextRange notifyDelegate:(BOOL)notifyDelegate;
- (void)scrollRangeToVisible:(NSRange)selectedTextRange;
+- (void)resetDictationRecognition;
// This protocol disallows direct access to `text` property because
// unwise usage of it can break the `attributeText` behavior.
diff --git a/Libraries/Text/TextInput/Singleline/RCTUITextField.mm b/Libraries/Text/TextInput/Singleline/RCTUITextField.mm
--- a/Libraries/Text/TextInput/Singleline/RCTUITextField.mm
+++ b/Libraries/Text/TextInput/Singleline/RCTUITextField.mm
@@ -197,6 +197,11 @@
}
#pragma mark - Dictation
+
+- (void)resetDictationRecognition
+{
+ _dictationRecognizing = NO;
+}
- (void)dictationRecordingDidEnd
{
diff --git a/Libraries/Text/TextInput/Multiline/RCTUITextView.mm b/Libraries/Text/TextInput/Multiline/RCTUITextView.mm
--- a/Libraries/Text/TextInput/Multiline/RCTUITextView.mm
+++ b/Libraries/Text/TextInput/Multiline/RCTUITextView.mm
@@ -319,6 +319,11 @@
#pragma mark - Dictation
+- (void)resetDictationRecognition
+{
+ _dictationRecognizing = NO;
+}
+
- (void)dictationRecordingDidEnd
{
_dictationRecognizing = YES;
diff --git a/Libraries/WebSocket/WebSocket.js b/Libraries/WebSocket/WebSocket.js
index 36aafbb..92aa2d9 100644
--- a/Libraries/WebSocket/WebSocket.js
+++ b/Libraries/WebSocket/WebSocket.js
@@ -88,6 +88,8 @@ class WebSocket extends EventTarget {
_eventEmitter: NativeEventEmitter<WebSocketEventDefinitions>;
_subscriptions: Array<EventSubscription>;
_binaryType: ?BinaryType;
+ // Orca: opt-in per socket; binary messages arrive as {base64} so the app decodes them natively.
+ orcaBinaryAsBase64: boolean = false;
bufferedAmount: number;
extension: ?string;
@@ -236,10 +238,13 @@ class WebSocket extends EventTarget {
if (ev.id !== this._socketId) {
return;
}
- let data: Blob | BlobData | ArrayBuffer | string = ev.data;
+ let data: Blob | BlobData | ArrayBuffer | string | {base64: string} =
+ ev.data;
switch (ev.type) {
case 'binary':
- data = base64.toByteArray(ev.data).buffer;
+ data = this.orcaBinaryAsBase64
+ ? {base64: ev.data}
+ : base64.toByteArray(ev.data).buffer;
break;
case 'blob':
data = BlobManager.createFromOptions(ev.data);