@react-native-ohos/react-native-reanimated 3.18.1-rc.6 → 3.18.2-rc.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (91) hide show
  1. package/LICENSE +21 -21
  2. package/README.OpenSource +10 -10
  3. package/README.md +10 -10
  4. package/harmony/reanimated/BuildProfile.ets +16 -16
  5. package/harmony/reanimated/build-profile.json5 +11 -11
  6. package/harmony/reanimated/oh-package.json5 +11 -11
  7. package/harmony/reanimated/src/main/cpp/Common/cpp/reanimated/AnimatedSensor/AnimatedSensorModule.cpp +86 -86
  8. package/harmony/reanimated/src/main/cpp/Common/cpp/reanimated/AnimatedSensor/AnimatedSensorModule.h +47 -47
  9. package/harmony/reanimated/src/main/cpp/Common/cpp/reanimated/Fabric/PropsRegistry.cpp +68 -68
  10. package/harmony/reanimated/src/main/cpp/Common/cpp/reanimated/Fabric/PropsRegistry.h +68 -68
  11. package/harmony/reanimated/src/main/cpp/Common/cpp/reanimated/Fabric/ReanimatedCommitHook.cpp +101 -101
  12. package/harmony/reanimated/src/main/cpp/Common/cpp/reanimated/Fabric/ReanimatedCommitHook.h +51 -51
  13. package/harmony/reanimated/src/main/cpp/Common/cpp/reanimated/Fabric/ReanimatedCommitShadowNode.h +49 -49
  14. package/harmony/reanimated/src/main/cpp/Common/cpp/reanimated/Fabric/ReanimatedMountHook.cpp +96 -87
  15. package/harmony/reanimated/src/main/cpp/Common/cpp/reanimated/Fabric/ReanimatedMountHook.h +33 -33
  16. package/harmony/reanimated/src/main/cpp/Common/cpp/reanimated/Fabric/ShadowTreeCloner.cpp +95 -95
  17. package/harmony/reanimated/src/main/cpp/Common/cpp/reanimated/Fabric/ShadowTreeCloner.h +29 -29
  18. package/harmony/reanimated/src/main/cpp/Common/cpp/reanimated/LayoutAnimations/LayoutAnimationType.h +9 -9
  19. package/harmony/reanimated/src/main/cpp/Common/cpp/reanimated/LayoutAnimations/LayoutAnimationsManager.cpp +232 -232
  20. package/harmony/reanimated/src/main/cpp/Common/cpp/reanimated/LayoutAnimations/LayoutAnimationsManager.h +90 -90
  21. package/harmony/reanimated/src/main/cpp/Common/cpp/reanimated/LayoutAnimations/LayoutAnimationsProxy.cpp +870 -870
  22. package/harmony/reanimated/src/main/cpp/Common/cpp/reanimated/LayoutAnimations/LayoutAnimationsProxy.h +147 -147
  23. package/harmony/reanimated/src/main/cpp/Common/cpp/reanimated/LayoutAnimations/LayoutAnimationsUtils.cpp +91 -91
  24. package/harmony/reanimated/src/main/cpp/Common/cpp/reanimated/LayoutAnimations/LayoutAnimationsUtils.h +176 -176
  25. package/harmony/reanimated/src/main/cpp/Common/cpp/reanimated/NativeModules/ReanimatedModuleProxy.cpp +971 -971
  26. package/harmony/reanimated/src/main/cpp/Common/cpp/reanimated/NativeModules/ReanimatedModuleProxy.h +252 -252
  27. package/harmony/reanimated/src/main/cpp/Common/cpp/reanimated/NativeModules/ReanimatedModuleProxySpec.cpp +231 -231
  28. package/harmony/reanimated/src/main/cpp/Common/cpp/reanimated/NativeModules/ReanimatedModuleProxySpec.h +109 -109
  29. package/harmony/reanimated/src/main/cpp/Common/cpp/reanimated/RuntimeDecorators/RNRuntimeDecorator.cpp +56 -56
  30. package/harmony/reanimated/src/main/cpp/Common/cpp/reanimated/RuntimeDecorators/RNRuntimeDecorator.h +20 -20
  31. package/harmony/reanimated/src/main/cpp/Common/cpp/reanimated/RuntimeDecorators/UIRuntimeDecorator.cpp +70 -70
  32. package/harmony/reanimated/src/main/cpp/Common/cpp/reanimated/RuntimeDecorators/UIRuntimeDecorator.h +35 -35
  33. package/harmony/reanimated/src/main/cpp/Common/cpp/reanimated/Tools/CollectionUtils.h +14 -14
  34. package/harmony/reanimated/src/main/cpp/Common/cpp/reanimated/Tools/FeaturesConfig.cpp +5 -5
  35. package/harmony/reanimated/src/main/cpp/Common/cpp/reanimated/Tools/FeaturesConfig.h +19 -19
  36. package/harmony/reanimated/src/main/cpp/Common/cpp/reanimated/Tools/PlatformDepMethodsHolder.h +98 -98
  37. package/harmony/reanimated/src/main/cpp/Common/cpp/reanimated/Tools/ReanimatedSystraceSection.h +135 -135
  38. package/harmony/reanimated/src/main/cpp/Common/cpp/worklets/NativeModules/WorkletsModuleProxy.cpp +47 -47
  39. package/harmony/reanimated/src/main/cpp/Common/cpp/worklets/NativeModules/WorkletsModuleProxy.h +59 -59
  40. package/harmony/reanimated/src/main/cpp/Common/cpp/worklets/NativeModules/WorkletsModuleProxySpec.cpp +27 -27
  41. package/harmony/reanimated/src/main/cpp/Common/cpp/worklets/NativeModules/WorkletsModuleProxySpec.h +25 -25
  42. package/harmony/reanimated/src/main/cpp/Common/cpp/worklets/Registries/EventHandlerRegistry.cpp +94 -94
  43. package/harmony/reanimated/src/main/cpp/Common/cpp/worklets/Registries/EventHandlerRegistry.h +49 -49
  44. package/harmony/reanimated/src/main/cpp/Common/cpp/worklets/Registries/WorkletRuntimeRegistry.cpp +8 -8
  45. package/harmony/reanimated/src/main/cpp/Common/cpp/worklets/Registries/WorkletRuntimeRegistry.h +39 -39
  46. package/harmony/reanimated/src/main/cpp/Common/cpp/worklets/SharedItems/Shareables.cpp +326 -326
  47. package/harmony/reanimated/src/main/cpp/Common/cpp/worklets/SharedItems/Shareables.h +345 -345
  48. package/harmony/reanimated/src/main/cpp/Common/cpp/worklets/Tools/AsyncQueue.cpp +52 -52
  49. package/harmony/reanimated/src/main/cpp/Common/cpp/worklets/Tools/AsyncQueue.h +35 -35
  50. package/harmony/reanimated/src/main/cpp/Common/cpp/worklets/Tools/Defs.h +10 -10
  51. package/harmony/reanimated/src/main/cpp/Common/cpp/worklets/Tools/JSISerializer.cpp +342 -342
  52. package/harmony/reanimated/src/main/cpp/Common/cpp/worklets/Tools/JSISerializer.h +47 -47
  53. package/harmony/reanimated/src/main/cpp/Common/cpp/worklets/Tools/JSLogger.cpp +16 -16
  54. package/harmony/reanimated/src/main/cpp/Common/cpp/worklets/Tools/JSLogger.h +20 -20
  55. package/harmony/reanimated/src/main/cpp/Common/cpp/worklets/Tools/JSScheduler.cpp +20 -20
  56. package/harmony/reanimated/src/main/cpp/Common/cpp/worklets/Tools/JSScheduler.h +29 -29
  57. package/harmony/reanimated/src/main/cpp/Common/cpp/worklets/Tools/PlatformLogger.h +16 -16
  58. package/harmony/reanimated/src/main/cpp/Common/cpp/worklets/Tools/ReanimatedJSIUtils.cpp +26 -26
  59. package/harmony/reanimated/src/main/cpp/Common/cpp/worklets/Tools/ReanimatedJSIUtils.h +199 -199
  60. package/harmony/reanimated/src/main/cpp/Common/cpp/worklets/Tools/ReanimatedVersion.cpp +95 -95
  61. package/harmony/reanimated/src/main/cpp/Common/cpp/worklets/Tools/ReanimatedVersion.h +19 -19
  62. package/harmony/reanimated/src/main/cpp/Common/cpp/worklets/Tools/SingleInstanceChecker.h +72 -72
  63. package/harmony/reanimated/src/main/cpp/Common/cpp/worklets/Tools/ThreadSafeQueue.h +49 -49
  64. package/harmony/reanimated/src/main/cpp/Common/cpp/worklets/Tools/UIScheduler.cpp +20 -20
  65. package/harmony/reanimated/src/main/cpp/Common/cpp/worklets/Tools/UIScheduler.h +22 -22
  66. package/harmony/reanimated/src/main/cpp/Common/cpp/worklets/Tools/WorkletEventHandler.cpp +29 -29
  67. package/harmony/reanimated/src/main/cpp/Common/cpp/worklets/Tools/WorkletEventHandler.h +41 -41
  68. package/harmony/reanimated/src/main/cpp/Common/cpp/worklets/WorkletRuntime/RNRuntimeWorkletDecorator.cpp +16 -16
  69. package/harmony/reanimated/src/main/cpp/Common/cpp/worklets/WorkletRuntime/RNRuntimeWorkletDecorator.h +19 -19
  70. package/harmony/reanimated/src/main/cpp/Common/cpp/worklets/WorkletRuntime/ReanimatedHermesRuntime.cpp +112 -112
  71. package/harmony/reanimated/src/main/cpp/Common/cpp/worklets/WorkletRuntime/ReanimatedHermesRuntime.h +127 -127
  72. package/harmony/reanimated/src/main/cpp/Common/cpp/worklets/WorkletRuntime/ReanimatedRuntime.cpp +53 -53
  73. package/harmony/reanimated/src/main/cpp/Common/cpp/worklets/WorkletRuntime/ReanimatedRuntime.h +22 -22
  74. package/harmony/reanimated/src/main/cpp/Common/cpp/worklets/WorkletRuntime/RuntimeInitialization.md +191 -191
  75. package/harmony/reanimated/src/main/cpp/Common/cpp/worklets/WorkletRuntime/WorkletRuntime.cpp +173 -155
  76. package/harmony/reanimated/src/main/cpp/Common/cpp/worklets/WorkletRuntime/WorkletRuntime.h +90 -90
  77. package/harmony/reanimated/src/main/cpp/Common/cpp/worklets/WorkletRuntime/WorkletRuntimeCollector.h +36 -36
  78. package/harmony/reanimated/src/main/cpp/Common/cpp/worklets/WorkletRuntime/WorkletRuntimeDecorator.cpp +189 -182
  79. package/harmony/reanimated/src/main/cpp/Common/cpp/worklets/WorkletRuntime/WorkletRuntimeDecorator.h +22 -22
  80. package/harmony/reanimated/src/main/cpp/WorkletsModule.cpp +60 -60
  81. package/harmony/reanimated/src/main/cpp/patches/AnimatedSensor/AnimatedSensorModule.cpp +89 -89
  82. package/harmony/reanimated/src/main/ets/ReanimatedModule.ts +7 -0
  83. package/harmony/reanimated/src/main/module.json5 +12 -12
  84. package/harmony/reanimated/src/main/resources/base/element/color.json +7 -7
  85. package/harmony/reanimated/src/main/resources/base/element/string.json +15 -15
  86. package/harmony/reanimated/src/main/resources/base/profile/main_pages.json +5 -5
  87. package/harmony/reanimated/src/main/resources/en_US/element/string.json +15 -15
  88. package/harmony/reanimated/src/main/resources/zh_CN/element/string.json +15 -15
  89. package/harmony/reanimated/ts.ts +6 -6
  90. package/harmony/reanimated.har +0 -0
  91. package/package.json +50 -50
@@ -1,971 +1,971 @@
1
- #include <jsi/jsi.h>
2
- #include <reanimated/NativeModules/ReanimatedModuleProxy.h>
3
- #include <reanimated/RuntimeDecorators/UIRuntimeDecorator.h>
4
- #include <reanimated/Tools/CollectionUtils.h>
5
- #include <reanimated/Tools/FeaturesConfig.h>
6
- #include <reanimated/Tools/ReanimatedSystraceSection.h>
7
- #include <unordered_map>
8
-
9
- #ifdef RCT_NEW_ARCH_ENABLED
10
- #include <reanimated/Fabric/ReanimatedCommitShadowNode.h>
11
- #include <reanimated/Fabric/ShadowTreeCloner.h>
12
- #endif // RCT_NEW_ARCH_ENABLED
13
-
14
- #include <worklets/Registries/EventHandlerRegistry.h>
15
- #include <worklets/SharedItems/Shareables.h>
16
- #include <worklets/Tools/AsyncQueue.h>
17
- #include <worklets/Tools/WorkletEventHandler.h>
18
-
19
- #ifdef __ANDROID__
20
- #include <fbjni/fbjni.h>
21
- #endif // __ANDROID__
22
-
23
- #ifdef RCT_NEW_ARCH_ENABLED
24
- #include <react/renderer/scheduler/Scheduler.h>
25
- #include <react/renderer/uimanager/UIManagerBinding.h>
26
- #include <react/renderer/uimanager/primitives.h>
27
- #endif // RCT_NEW_ARCH_ENABLED
28
-
29
- #include <functional>
30
- #include <utility>
31
-
32
- #ifdef RCT_NEW_ARCH_ENABLED
33
- #include <iomanip>
34
- #include <sstream>
35
- #include <string>
36
- #endif // RCT_NEW_ARCH_ENABLED
37
-
38
- namespace reanimated {
39
-
40
- ReanimatedModuleProxy::ReanimatedModuleProxy(
41
- const std::shared_ptr<WorkletsModuleProxy> &workletsModuleProxy,
42
- jsi::Runtime &rnRuntime,
43
- const std::shared_ptr<CallInvoker> &jsCallInvoker,
44
- const PlatformDepMethodsHolder &platformDepMethodsHolder,
45
- const bool isBridgeless,
46
- const bool isReducedMotion)
47
- : ReanimatedModuleProxySpec(jsCallInvoker),
48
- isBridgeless_(isBridgeless),
49
- isReducedMotion_(isReducedMotion),
50
- workletsModuleProxy_(workletsModuleProxy),
51
- valueUnpackerCode_(workletsModuleProxy->getValueUnpackerCode()),
52
- uiWorkletRuntime_(std::make_shared<WorkletRuntime>(
53
- rnRuntime,
54
- workletsModuleProxy->getJSQueue(),
55
- workletsModuleProxy->getJSScheduler(),
56
- "Reanimated UI runtime",
57
- true /* supportsLocking */,
58
- valueUnpackerCode_)),
59
- eventHandlerRegistry_(std::make_unique<EventHandlerRegistry>()),
60
- requestRender_(platformDepMethodsHolder.requestRender),
61
- animatedSensorModule_(platformDepMethodsHolder),
62
- jsLogger_(
63
- std::make_shared<JSLogger>(workletsModuleProxy->getJSScheduler())),
64
- layoutAnimationsManager_(
65
- std::make_shared<LayoutAnimationsManager>(jsLogger_)),
66
- #ifdef RCT_NEW_ARCH_ENABLED
67
- propsRegistry_(std::make_shared<PropsRegistry>()),
68
- #else
69
- obtainPropFunction_(platformDepMethodsHolder.obtainPropFunction),
70
- configurePropsPlatformFunction_(
71
- platformDepMethodsHolder.configurePropsFunction),
72
- updatePropsFunction_(platformDepMethodsHolder.updatePropsFunction),
73
- #endif
74
- subscribeForKeyboardEventsFunction_(
75
- platformDepMethodsHolder.subscribeForKeyboardEvents),
76
- unsubscribeFromKeyboardEventsFunction_(
77
- platformDepMethodsHolder.unsubscribeFromKeyboardEvents) {
78
- }
79
-
80
- void ReanimatedModuleProxy::init(
81
- const PlatformDepMethodsHolder &platformDepMethodsHolder) {
82
- auto onRenderCallback = [weakThis =
83
- weak_from_this()](const double timestampMs) {
84
- auto strongThis = weakThis.lock();
85
- if (!strongThis) {
86
- return;
87
- }
88
-
89
- strongThis->renderRequested_ = false;
90
- strongThis->onRender(timestampMs);
91
- };
92
- onRenderCallback_ = std::move(onRenderCallback);
93
-
94
- auto requestAnimationFrame = [weakThis = weak_from_this()](
95
- jsi::Runtime &rt,
96
- const jsi::Value &callback) {
97
- auto strongThis = weakThis.lock();
98
- if (!strongThis) {
99
- return;
100
- }
101
-
102
- strongThis->requestAnimationFrame(rt, callback);
103
- };
104
-
105
- #ifdef RCT_NEW_ARCH_ENABLED
106
- auto updateProps = [weakThis = weak_from_this()](
107
- jsi::Runtime &rt, const jsi::Value &operations) {
108
- auto strongThis = weakThis.lock();
109
- if (!strongThis) {
110
- return;
111
- }
112
-
113
- strongThis->updateProps(rt, operations);
114
- };
115
-
116
- auto removeFromPropsRegistry = [weakThis = weak_from_this()](
117
- jsi::Runtime &rt,
118
- const jsi::Value &viewTags) {
119
- auto strongThis = weakThis.lock();
120
- if (!strongThis) {
121
- return;
122
- }
123
-
124
- strongThis->removeFromPropsRegistry(rt, viewTags);
125
- };
126
-
127
- auto measure = [weakThis = weak_from_this()](
128
- jsi::Runtime &rt,
129
- const jsi::Value &shadowNodeValue) -> jsi::Value {
130
- auto strongThis = weakThis.lock();
131
- if (!strongThis) {
132
- return jsi::Value::undefined();
133
- }
134
- return strongThis->measure(rt, shadowNodeValue);
135
- };
136
-
137
- auto dispatchCommand = [weakThis = weak_from_this()](
138
- jsi::Runtime &rt,
139
- const jsi::Value &shadowNodeValue,
140
- const jsi::Value &commandNameValue,
141
- const jsi::Value &argsValue) {
142
- auto strongThis = weakThis.lock();
143
- if (!strongThis) {
144
- return;
145
- }
146
-
147
- strongThis->dispatchCommand(
148
- rt, shadowNodeValue, commandNameValue, argsValue);
149
- };
150
- ProgressLayoutAnimationFunction progressLayoutAnimation =
151
- [weakThis = weak_from_this()](
152
- jsi::Runtime &rt, int tag, const jsi::Object &newStyle, bool) {
153
- auto strongThis = weakThis.lock();
154
- if (!strongThis) {
155
- return;
156
- }
157
-
158
- auto surfaceId =
159
- strongThis->layoutAnimationsProxy_->progressLayoutAnimation(
160
- tag, newStyle);
161
- if (!surfaceId) {
162
- return;
163
- }
164
- strongThis->uiManager_->getShadowTreeRegistry().visit(
165
- *surfaceId, [](const ShadowTree &shadowTree) {
166
- shadowTree.notifyDelegatesOfUpdates();
167
- });
168
- };
169
-
170
- EndLayoutAnimationFunction endLayoutAnimation =
171
- [weakThis = weak_from_this()](int tag, bool shouldRemove) {
172
- auto strongThis = weakThis.lock();
173
- if (!strongThis) {
174
- return;
175
- }
176
-
177
- auto surfaceId = strongThis->layoutAnimationsProxy_->endLayoutAnimation(
178
- tag, shouldRemove);
179
- if (!surfaceId) {
180
- return;
181
- }
182
-
183
- strongThis->uiManager_->getShadowTreeRegistry().visit(
184
- *surfaceId, [](const ShadowTree &shadowTree) {
185
- shadowTree.notifyDelegatesOfUpdates();
186
- });
187
- };
188
-
189
- auto obtainProp = [weakThis = weak_from_this()](
190
- jsi::Runtime &rt,
191
- const jsi::Value &shadowNodeWrapper,
192
- const jsi::Value &propName) {
193
- auto strongThis = weakThis.lock();
194
- if (!strongThis) {
195
- return jsi::String::createFromUtf8(rt, "");
196
- }
197
-
198
- return strongThis->obtainProp(rt, shadowNodeWrapper, propName);
199
- };
200
- #endif
201
-
202
- jsi::Runtime &uiRuntime = uiWorkletRuntime_->getJSIRuntime();
203
- UIRuntimeDecorator::decorate(
204
- uiRuntime,
205
- #ifdef RCT_NEW_ARCH_ENABLED
206
- obtainProp,
207
- updateProps,
208
- measure,
209
- dispatchCommand,
210
- #else
211
- platformDepMethodsHolder.scrollToFunction,
212
- platformDepMethodsHolder.obtainPropFunction,
213
- platformDepMethodsHolder.updatePropsFunction,
214
- platformDepMethodsHolder.measureFunction,
215
- platformDepMethodsHolder.dispatchCommandFunction,
216
- #endif
217
- requestAnimationFrame,
218
- platformDepMethodsHolder.getAnimationTimestamp,
219
- platformDepMethodsHolder.setGestureStateFunction,
220
- #ifdef RCT_NEW_ARCH_ENABLED
221
- progressLayoutAnimation,
222
- endLayoutAnimation,
223
- #else
224
- platformDepMethodsHolder.progressLayoutAnimation,
225
- platformDepMethodsHolder.endLayoutAnimation,
226
- #endif
227
- platformDepMethodsHolder.maybeFlushUIUpdatesQueueFunction);
228
- }
229
-
230
- ReanimatedModuleProxy::~ReanimatedModuleProxy() {
231
- // event handler registry and frame callbacks store some JSI values from UI
232
- // runtime, so they have to go away before we tear down the runtime
233
- eventHandlerRegistry_.reset();
234
- frameCallbacks_.clear();
235
- #ifdef RCT_NEW_ARCH_ENABLED
236
- operationsInBatch_.clear();
237
- #endif // RCT_NEW_ARCH_ENABLED
238
- uiWorkletRuntime_.reset();
239
- }
240
-
241
- void ReanimatedModuleProxy::scheduleOnUI(
242
- jsi::Runtime &rt,
243
- const jsi::Value &worklet) {
244
- auto shareableWorklet = extractShareableOrThrow<ShareableWorklet>(
245
- rt, worklet, "[Reanimated] Only worklets can be scheduled to run on UI.");
246
- workletsModuleProxy_->getUIScheduler()->scheduleOnUI(
247
- [=, weakThis = weak_from_this()] {
248
- const auto strongThis = weakThis.lock();
249
- if (!strongThis) {
250
- return;
251
- }
252
- #if JS_RUNTIME_HERMES
253
- // JSI's scope defined here allows for JSI-objects to be cleared up
254
- // after each runtime loop. Within these loops we typically create some
255
- // temporary JSI objects and hence it allows for such objects to be
256
- // garbage collected much sooner. Apparently the scope API is only
257
- // supported on Hermes at the moment.
258
- const auto scope =
259
- jsi::Scope(strongThis->uiWorkletRuntime_->getJSIRuntime());
260
- #endif
261
- strongThis->uiWorkletRuntime_->runGuarded(shareableWorklet);
262
- });
263
- }
264
-
265
- jsi::Value ReanimatedModuleProxy::executeOnUIRuntimeSync(
266
- jsi::Runtime &rt,
267
- const jsi::Value &worklet) {
268
- return uiWorkletRuntime_->executeSync(rt, worklet);
269
- }
270
-
271
- jsi::Value ReanimatedModuleProxy::createWorkletRuntime(
272
- jsi::Runtime &rt,
273
- const jsi::Value &name,
274
- const jsi::Value &initializer) {
275
- auto workletRuntime = std::make_shared<WorkletRuntime>(
276
- rt,
277
- workletsModuleProxy_->getJSQueue(),
278
- workletsModuleProxy_->getJSScheduler(),
279
- name.asString(rt).utf8(rt),
280
- true /* supportsLocking */,
281
- valueUnpackerCode_);
282
- auto initializerShareable = extractShareableOrThrow<ShareableWorklet>(
283
- rt, initializer, "[Reanimated] Initializer must be a worklet.");
284
- workletRuntime->runGuarded(initializerShareable);
285
- return jsi::Object::createFromHostObject(rt, workletRuntime);
286
- }
287
-
288
- jsi::Value ReanimatedModuleProxy::scheduleOnRuntime(
289
- jsi::Runtime &rt,
290
- const jsi::Value &workletRuntimeValue,
291
- const jsi::Value &shareableWorkletValue) {
292
- reanimated::scheduleOnRuntime(rt, workletRuntimeValue, shareableWorkletValue);
293
- return jsi::Value::undefined();
294
- }
295
-
296
- jsi::Value ReanimatedModuleProxy::registerEventHandler(
297
- jsi::Runtime &rt,
298
- const jsi::Value &worklet,
299
- const jsi::Value &eventName,
300
- const jsi::Value &emitterReactTag) {
301
- static uint64_t NEXT_EVENT_HANDLER_ID = 1;
302
-
303
- uint64_t newRegistrationId = NEXT_EVENT_HANDLER_ID++;
304
- auto eventNameStr = eventName.asString(rt).utf8(rt);
305
- auto handlerShareable = extractShareableOrThrow<ShareableWorklet>(
306
- rt, worklet, "[Reanimated] Event handler must be a worklet.");
307
- int emitterReactTagInt = emitterReactTag.asNumber();
308
-
309
- workletsModuleProxy_->getUIScheduler()->scheduleOnUI(
310
- [=, weakThis = weak_from_this()]() {
311
- auto strongThis = weakThis.lock();
312
- if (!strongThis) {
313
- return;
314
- }
315
- auto handler = std::make_shared<WorkletEventHandler>(
316
- newRegistrationId,
317
- eventNameStr,
318
- emitterReactTagInt,
319
- handlerShareable);
320
- strongThis->eventHandlerRegistry_->registerEventHandler(
321
- std::move(handler));
322
- });
323
-
324
- return jsi::Value(static_cast<double>(newRegistrationId));
325
- }
326
-
327
- void ReanimatedModuleProxy::unregisterEventHandler(
328
- jsi::Runtime &,
329
- const jsi::Value &registrationId) {
330
- uint64_t id = registrationId.asNumber();
331
- workletsModuleProxy_->getUIScheduler()->scheduleOnUI(
332
- [=, weakThis = weak_from_this()]() {
333
- auto strongThis = weakThis.lock();
334
- if (!strongThis) {
335
- return;
336
- }
337
- strongThis->eventHandlerRegistry_->unregisterEventHandler(id);
338
- });
339
- }
340
-
341
- #ifdef RCT_NEW_ARCH_ENABLED
342
- static inline std::string intColorToHex(const int val) {
343
- std::stringstream
344
- invertedHexColorStream; // By default transparency is first, color second
345
- invertedHexColorStream << std::setfill('0') << std::setw(8) << std::hex
346
- << val;
347
-
348
- auto invertedHexColor = invertedHexColorStream.str();
349
- auto hexColor =
350
- "#" + invertedHexColor.substr(2, 6) + invertedHexColor.substr(0, 2);
351
-
352
- return hexColor;
353
- }
354
-
355
- std::string ReanimatedModuleProxy::obtainPropFromShadowNode(
356
- jsi::Runtime &rt,
357
- const std::string &propName,
358
- const ShadowNode::Shared &shadowNode) {
359
- auto newestCloneOfShadowNode =
360
- uiManager_->getNewestCloneOfShadowNode(*shadowNode);
361
-
362
- if (propName == "width" || propName == "height" || propName == "top" ||
363
- propName == "left") {
364
- // These props are calculated from frame
365
- auto layoutableShadowNode = dynamic_cast<LayoutableShadowNode const *>(
366
- newestCloneOfShadowNode.get());
367
- const auto &frame = layoutableShadowNode->layoutMetrics_.frame;
368
-
369
- if (propName == "width") {
370
- return std::to_string(frame.size.width);
371
- } else if (propName == "height") {
372
- return std::to_string(frame.size.height);
373
- } else if (propName == "top") {
374
- return std::to_string(frame.origin.y);
375
- } else if (propName == "left") {
376
- return std::to_string(frame.origin.x);
377
- }
378
- } else {
379
- // These props are calculated from viewProps
380
- auto props = newestCloneOfShadowNode->getProps();
381
- auto viewProps = std::static_pointer_cast<const ViewProps>(props);
382
- if (propName == "opacity") {
383
- return std::to_string(viewProps->opacity);
384
- } else if (propName == "zIndex") {
385
- if (viewProps->zIndex.has_value()) {
386
- return std::to_string(*viewProps->zIndex);
387
- }
388
- } else if (propName == "backgroundColor") {
389
- return intColorToHex(*viewProps->backgroundColor);
390
- }
391
- }
392
-
393
- throw std::runtime_error(std::string(
394
- "Getting property `" + propName +
395
- "` with function `getViewProp` is not supported"));
396
- }
397
-
398
- jsi::Value ReanimatedModuleProxy::getViewProp(
399
- jsi::Runtime &rnRuntime,
400
- const jsi::Value &shadowNodeWrapper,
401
- const jsi::Value &propName,
402
- const jsi::Value &callback) {
403
- const auto propNameStr = propName.asString(rnRuntime).utf8(rnRuntime);
404
- const auto funPtr = std::make_shared<jsi::Function>(
405
- callback.getObject(rnRuntime).asFunction(rnRuntime));
406
- const auto shadowNode = shadowNodeFromValue(rnRuntime, shadowNodeWrapper);
407
- workletsModuleProxy_->getUIScheduler()->scheduleOnUI(
408
- [=, weakThis = weak_from_this()]() {
409
- auto strongThis = weakThis.lock();
410
- if (!strongThis) {
411
- return;
412
- }
413
- jsi::Runtime &uiRuntime =
414
- strongThis->uiWorkletRuntime_->getJSIRuntime();
415
- const auto resultStr = strongThis->obtainPropFromShadowNode(
416
- uiRuntime, propNameStr, shadowNode);
417
-
418
- strongThis->workletsModuleProxy_->getJSScheduler()->scheduleOnJS(
419
- [=](jsi::Runtime &rnRuntime) {
420
- const auto resultValue =
421
- jsi::String::createFromUtf8(rnRuntime, resultStr);
422
- funPtr->call(rnRuntime, resultValue);
423
- });
424
- });
425
- return jsi::Value::undefined();
426
- }
427
-
428
- #else
429
-
430
- jsi::Value ReanimatedModuleProxy::getViewProp(
431
- jsi::Runtime &rnRuntime,
432
- const jsi::Value &viewTag,
433
- const jsi::Value &propName,
434
- const jsi::Value &callback) {
435
- const auto propNameStr = propName.asString(rnRuntime).utf8(rnRuntime);
436
- const auto funPtr = std::make_shared<jsi::Function>(
437
- callback.getObject(rnRuntime).asFunction(rnRuntime));
438
-
439
- const int viewTagInt = viewTag.asNumber();
440
-
441
- workletsModuleProxy_->getUIScheduler()->scheduleOnUI(
442
- [=, weakThis = weak_from_this()]
443
-
444
- () {
445
- auto strongThis = weakThis.lock();
446
- if (!strongThis) {
447
- return;
448
- }
449
- jsi::Runtime &uiRuntime =
450
- strongThis->uiWorkletRuntime_->getJSIRuntime();
451
- const jsi::Value propNameValue =
452
- jsi::String::createFromUtf8(uiRuntime, propNameStr);
453
- const auto resultValue = strongThis->obtainPropFunction_(
454
- uiRuntime, viewTagInt, propNameValue);
455
- const auto resultStr = resultValue.asString(uiRuntime).utf8(uiRuntime);
456
- const auto jsScheduler =
457
- strongThis->workletsModuleProxy_->getJSScheduler();
458
- jsScheduler->scheduleOnJS([=](jsi::Runtime &rnRuntime) {
459
- const auto resultValue =
460
- jsi::String::createFromUtf8(rnRuntime, resultStr);
461
- funPtr->call(rnRuntime, resultValue);
462
- });
463
- });
464
- return jsi::Value::undefined();
465
- }
466
-
467
- #endif
468
-
469
- jsi::Value ReanimatedModuleProxy::enableLayoutAnimations(
470
- jsi::Runtime &,
471
- const jsi::Value &config) {
472
- FeaturesConfig::setLayoutAnimationEnabled(config.getBool());
473
- return jsi::Value::undefined();
474
- }
475
-
476
- jsi::Value ReanimatedModuleProxy::configureProps(
477
- jsi::Runtime &rt,
478
- const jsi::Value &uiProps,
479
- const jsi::Value &nativeProps) {
480
- #ifdef RCT_NEW_ARCH_ENABLED
481
- auto uiPropsArray = uiProps.asObject(rt).asArray(rt);
482
- for (size_t i = 0; i < uiPropsArray.size(rt); ++i) {
483
- auto name = uiPropsArray.getValueAtIndex(rt, i).asString(rt).utf8(rt);
484
- animatablePropNames_.insert(name);
485
- }
486
- auto nativePropsArray = nativeProps.asObject(rt).asArray(rt);
487
- for (size_t i = 0; i < nativePropsArray.size(rt); ++i) {
488
- auto name = nativePropsArray.getValueAtIndex(rt, i).asString(rt).utf8(rt);
489
- animatablePropNames_.insert(name);
490
- }
491
- #else
492
- configurePropsPlatformFunction_(rt, uiProps, nativeProps);
493
- #endif // RCT_NEW_ARCH_ENABLED
494
-
495
- return jsi::Value::undefined();
496
- }
497
-
498
- jsi::Value ReanimatedModuleProxy::configureLayoutAnimationBatch(
499
- jsi::Runtime &rt,
500
- const jsi::Value &layoutAnimationsBatch) {
501
- auto array = layoutAnimationsBatch.asObject(rt).asArray(rt);
502
- size_t length = array.size(rt);
503
- std::vector<LayoutAnimationConfig> batch(length);
504
- for (int i = 0; i < length; i++) {
505
- auto item = array.getValueAtIndex(rt, i).asObject(rt);
506
- auto &batchItem = batch[i];
507
- batchItem.tag = item.getProperty(rt, "viewTag").asNumber();
508
- batchItem.type = static_cast<LayoutAnimationType>(
509
- item.getProperty(rt, "type").asNumber());
510
- auto config = item.getProperty(rt, "config");
511
- if (config.isUndefined()) {
512
- batchItem.config = nullptr;
513
- } else {
514
- batchItem.config = extractShareableOrThrow<ShareableObject>(
515
- rt,
516
- config,
517
- "[Reanimated] Layout animation config must be an object.");
518
- }
519
- if (batch[i].type != SHARED_ELEMENT_TRANSITION &&
520
- batch[i].type != SHARED_ELEMENT_TRANSITION_PROGRESS) {
521
- continue;
522
- }
523
- auto sharedTransitionTag = item.getProperty(rt, "sharedTransitionTag");
524
- if (sharedTransitionTag.isUndefined()) {
525
- batch[i].config = nullptr;
526
- } else {
527
- batch[i].sharedTransitionTag = sharedTransitionTag.asString(rt).utf8(rt);
528
- }
529
- }
530
- layoutAnimationsManager_->configureAnimationBatch(batch);
531
- return jsi::Value::undefined();
532
- }
533
-
534
- void ReanimatedModuleProxy::setShouldAnimateExiting(
535
- jsi::Runtime &rt,
536
- const jsi::Value &viewTag,
537
- const jsi::Value &shouldAnimate) {
538
- layoutAnimationsManager_->setShouldAnimateExiting(
539
- viewTag.asNumber(), shouldAnimate.getBool());
540
- }
541
-
542
- bool ReanimatedModuleProxy::isAnyHandlerWaitingForEvent(
543
- const std::string &eventName,
544
- const int emitterReactTag) {
545
- return eventHandlerRegistry_->isAnyHandlerWaitingForEvent(
546
- eventName, emitterReactTag);
547
- }
548
-
549
- void ReanimatedModuleProxy::requestAnimationFrame(
550
- jsi::Runtime &rt,
551
- const jsi::Value &callback) {
552
- frameCallbacks_.push_back(std::make_shared<jsi::Value>(rt, callback));
553
- maybeRequestRender();
554
- }
555
-
556
- void ReanimatedModuleProxy::maybeRequestRender() {
557
- if (!renderRequested_) {
558
- renderRequested_ = true;
559
- requestRender_(onRenderCallback_);
560
- }
561
- }
562
-
563
- void ReanimatedModuleProxy::onRender(double timestampMs) {
564
- auto callbacks = std::move(frameCallbacks_);
565
- frameCallbacks_.clear();
566
- jsi::Runtime &uiRuntime = uiWorkletRuntime_->getJSIRuntime();
567
- jsi::Value timestamp{timestampMs};
568
- for (const auto &callback : callbacks) {
569
- runOnRuntimeGuarded(uiRuntime, *callback, timestamp);
570
- }
571
- }
572
-
573
- jsi::Value ReanimatedModuleProxy::registerSensor(
574
- jsi::Runtime &rt,
575
- const jsi::Value &sensorType,
576
- const jsi::Value &interval,
577
- const jsi::Value &iosReferenceFrame,
578
- const jsi::Value &sensorDataHandler) {
579
- return animatedSensorModule_.registerSensor(
580
- rt,
581
- uiWorkletRuntime_,
582
- sensorType,
583
- interval,
584
- iosReferenceFrame,
585
- sensorDataHandler);
586
- }
587
-
588
- void ReanimatedModuleProxy::unregisterSensor(
589
- jsi::Runtime &,
590
- const jsi::Value &sensorId) {
591
- animatedSensorModule_.unregisterSensor(sensorId);
592
- }
593
-
594
- void ReanimatedModuleProxy::cleanupSensors() {
595
- animatedSensorModule_.unregisterAllSensors();
596
- }
597
-
598
- #ifdef RCT_NEW_ARCH_ENABLED
599
-
600
- void ReanimatedModuleProxy::markNodeAsRemovable(
601
- jsi::Runtime &rt,
602
- const jsi::Value &shadowNodeWrapper) {
603
- auto shadowNode = shadowNodeFromValue(rt, shadowNodeWrapper);
604
- propsRegistry_->markNodeAsRemovable(shadowNode);
605
- }
606
-
607
- void ReanimatedModuleProxy::unmarkNodeAsRemovable(
608
- jsi::Runtime &rt,
609
- const jsi::Value &viewTag) {
610
- propsRegistry_->unmarkNodeAsRemovable(viewTag.asNumber());
611
- }
612
-
613
- jsi::Value ReanimatedModuleProxy::filterNonAnimatableProps(
614
- jsi::Runtime &rt,
615
- const jsi::Value &props) {
616
- jsi::Object nonAnimatableProps(rt);
617
- bool hasAnyNonAnimatableProp = false;
618
- const jsi::Object &propsObject = props.asObject(rt);
619
- const jsi::Array &propNames = propsObject.getPropertyNames(rt);
620
- for (size_t i = 0; i < propNames.size(rt); ++i) {
621
- const std::string &propName =
622
- propNames.getValueAtIndex(rt, i).asString(rt).utf8(rt);
623
- if (!collection::contains(animatablePropNames_, propName)) {
624
- hasAnyNonAnimatableProp = true;
625
- const auto &propNameStr = propName.c_str();
626
- const jsi::Value &propValue = propsObject.getProperty(rt, propNameStr);
627
- nonAnimatableProps.setProperty(rt, propNameStr, propValue);
628
- }
629
- }
630
- if (!hasAnyNonAnimatableProp) {
631
- return jsi::Value::undefined();
632
- }
633
- return nonAnimatableProps;
634
- }
635
- #endif // RCT_NEW_ARCH_ENABLED
636
-
637
- bool ReanimatedModuleProxy::handleEvent(
638
- const std::string &eventName,
639
- const int emitterReactTag,
640
- const jsi::Value &payload,
641
- double currentTime) {
642
- eventHandlerRegistry_->processEvent(
643
- uiWorkletRuntime_, currentTime, eventName, emitterReactTag, payload);
644
-
645
- // TODO: return true if Reanimated successfully handled the event
646
- // to avoid sending it to JavaScript
647
- return false;
648
- }
649
-
650
- #ifdef RCT_NEW_ARCH_ENABLED
651
- bool ReanimatedModuleProxy::handleRawEvent(
652
- const RawEvent &rawEvent,
653
- double currentTime) {
654
- const EventTarget *eventTarget = rawEvent.eventTarget.get();
655
- if (eventTarget == nullptr) {
656
- // after app reload scrollView is unmounted and its content offset is set
657
- // to 0 and view is thrown into recycle pool setting content offset
658
- // triggers scroll event eventTarget is null though, because it's
659
- // unmounting we can just ignore this event, because it's an event on
660
- // unmounted component
661
- return false;
662
- }
663
-
664
- int tag = eventTarget->getTag();
665
- auto eventType = rawEvent.type;
666
- if (eventType.rfind("top", 0) == 0) {
667
- eventType = "on" + eventType.substr(3);
668
- }
669
- jsi::Runtime &rt = uiWorkletRuntime_->getJSIRuntime();
670
-
671
- if (!isAnyHandlerWaitingForEvent(eventType, tag)) {
672
- return false;
673
- }
674
-
675
- const auto &eventPayload = rawEvent.eventPayload;
676
- jsi::Value payload = eventPayload->asJSIValue(rt);
677
-
678
- auto res = handleEvent(eventType, tag, std::move(payload), currentTime);
679
- // TODO: we should call performOperations conditionally if event is handled
680
- // (res == true), but for now handleEvent always returns false. Thankfully,
681
- // performOperations does not trigger a lot of code if there is nothing to
682
- // be done so this is fine for now.
683
- performOperations();
684
- return res;
685
- }
686
-
687
- void ReanimatedModuleProxy::updateProps(
688
- jsi::Runtime &rt,
689
- const jsi::Value &operations) {
690
- auto array = operations.asObject(rt).asArray(rt);
691
- size_t length = array.size(rt);
692
- for (size_t i = 0; i < length; ++i) {
693
- auto item = array.getValueAtIndex(rt, i).asObject(rt);
694
- auto shadowNodeWrapper = item.getProperty(rt, "shadowNodeWrapper");
695
- auto shadowNode = shadowNodeFromValue(rt, shadowNodeWrapper);
696
- const jsi::Value &updates = item.getProperty(rt, "updates");
697
- operationsInBatch_.emplace_back(
698
- shadowNode, std::make_unique<jsi::Value>(rt, updates));
699
- }
700
- }
701
-
702
- void ReanimatedModuleProxy::performOperations() {
703
- if (operationsInBatch_.empty() && tagsToRemove_.empty()) {
704
- // nothing to do
705
- return;
706
- }
707
-
708
- ReanimatedSystraceSection s("performOperations");
709
-
710
- auto copiedOperationsQueue = std::move(operationsInBatch_);
711
- operationsInBatch_.clear();
712
-
713
- jsi::Runtime &rt = uiWorkletRuntime_->getJSIRuntime();
714
-
715
- {
716
- auto lock = propsRegistry_->createLock();
717
-
718
- if (copiedOperationsQueue.size() > 0 &&
719
- propsRegistry_->shouldReanimatedSkipCommit()) {
720
- propsRegistry_->pleaseCommitAfterPause();
721
- }
722
-
723
- // remove recently unmounted ShadowNodes from PropsRegistry
724
- if (!tagsToRemove_.empty()) {
725
- for (auto tag : tagsToRemove_) {
726
- propsRegistry_->remove(tag);
727
- }
728
- tagsToRemove_.clear();
729
- }
730
-
731
- // Even if only non-layout props are changed, we need to store the update
732
- // in PropsRegistry anyway so that React doesn't overwrite it in the next
733
- // render. Currently, only opacity and transform are treated in a special
734
- // way but backgroundColor, shadowOpacity etc. would get overwritten (see
735
- // `_propKeysManagedByAnimated_DO_NOT_USE_THIS_IS_BROKEN`).
736
- for (const auto &[shadowNode, props] : copiedOperationsQueue) {
737
- propsRegistry_->update(shadowNode, dynamicFromValue(rt, *props));
738
- }
739
- }
740
-
741
- for (const auto &[shadowNode, props] : copiedOperationsQueue) {
742
- const jsi::Value &nonAnimatableProps = filterNonAnimatableProps(rt, *props);
743
- if (nonAnimatableProps.isUndefined()) {
744
- continue;
745
- }
746
- Tag viewTag = shadowNode->getTag();
747
- jsi::Value maybeJSPropsUpdater =
748
- rt.global().getProperty(rt, "updateJSProps");
749
- assert(
750
- maybeJSPropsUpdater.isObject() &&
751
- "[Reanimated] `updateJSProps` not found");
752
- jsi::Function jsPropsUpdater =
753
- maybeJSPropsUpdater.asObject(rt).asFunction(rt);
754
- jsPropsUpdater.call(rt, viewTag, nonAnimatableProps);
755
- }
756
-
757
- if (propsRegistry_->shouldReanimatedSkipCommit()) {
758
- // It may happen that `performOperations` is called on the UI thread
759
- // while React Native tries to commit a new tree on the JS thread.
760
- // In this case, we should skip the commit here and let React Native do
761
- // it. The commit will include the current values from PropsRegistry which
762
- // will be applied in ReanimatedCommitHook.
763
- return;
764
- }
765
-
766
- react_native_assert(uiManager_ != nullptr);
767
- const auto &shadowTreeRegistry = uiManager_->getShadowTreeRegistry();
768
-
769
- std::unordered_map<SurfaceId, PropsMap> propsMapBySurface;
770
-
771
- for (auto const &[shadowNode, props] : copiedOperationsQueue) {
772
- SurfaceId surfaceId = shadowNode->getSurfaceId();
773
- auto family = &shadowNode->getFamily();
774
- react_native_assert(family->getSurfaceId() == surfaceId);
775
- propsMapBySurface[surfaceId][family].emplace_back(rt, std::move(*props));
776
- }
777
-
778
- for (auto const &[surfaceId, propsMap] : propsMapBySurface) {
779
- shadowTreeRegistry.visit(surfaceId, [&](ShadowTree const &shadowTree) {
780
- shadowTree.commit(
781
- [&](RootShadowNode const &oldRootShadowNode)
782
- -> RootShadowNode::Unshared {
783
- if (propsRegistry_->shouldReanimatedSkipCommit()) {
784
- return nullptr;
785
- }
786
-
787
- auto rootNode =
788
- cloneShadowTreeWithNewProps(oldRootShadowNode, propsMap);
789
-
790
- // Mark the commit as Reanimated commit so that we can distinguish
791
- // it in ReanimatedCommitHook.
792
-
793
- auto reaShadowNode =
794
- std::reinterpret_pointer_cast<ReanimatedCommitShadowNode>(
795
- rootNode);
796
- reaShadowNode->setReanimatedCommitTrait();
797
-
798
- return rootNode;
799
- },
800
- {/* .enableStateReconciliation = */
801
- false,
802
- /* .mountSynchronously = */ true});
803
- });
804
- }
805
- }
806
-
807
- void ReanimatedModuleProxy::dispatchCommand(
808
- jsi::Runtime &rt,
809
- const jsi::Value &shadowNodeValue,
810
- const jsi::Value &commandNameValue,
811
- const jsi::Value &argsValue) {
812
- ShadowNode::Shared shadowNode = shadowNodeFromValue(rt, shadowNodeValue);
813
- std::string commandName = stringFromValue(rt, commandNameValue);
814
- folly::dynamic args = commandArgsFromValue(rt, argsValue);
815
- const auto &scheduler = static_cast<Scheduler *>(uiManager_->getDelegate());
816
-
817
- if (!scheduler) {
818
- return;
819
- }
820
-
821
- const auto &schedulerDelegate = scheduler->getDelegate();
822
-
823
- if (schedulerDelegate) {
824
- const auto shadowView = ShadowView(*shadowNode);
825
- schedulerDelegate->schedulerDidDispatchCommand(
826
- shadowView, commandName, args);
827
- }
828
- }
829
-
830
- jsi::String ReanimatedModuleProxy::obtainProp(
831
- jsi::Runtime &rt,
832
- const jsi::Value &shadowNodeWrapper,
833
- const jsi::Value &propName) {
834
- jsi::Runtime &uiRuntime = uiWorkletRuntime_->getJSIRuntime();
835
- const auto propNameStr = propName.asString(rt).utf8(rt);
836
- const auto shadowNode = shadowNodeFromValue(rt, shadowNodeWrapper);
837
- const auto resultStr =
838
- obtainPropFromShadowNode(uiRuntime, propNameStr, shadowNode);
839
- return jsi::String::createFromUtf8(rt, resultStr);
840
- }
841
-
842
- jsi::Value ReanimatedModuleProxy::measure(
843
- jsi::Runtime &rt,
844
- const jsi::Value &shadowNodeValue) {
845
- // based on implementation from UIManagerBinding.cpp
846
-
847
- auto shadowNode = shadowNodeFromValue(rt, shadowNodeValue);
848
- auto layoutMetrics = uiManager_->getRelativeLayoutMetrics(
849
- *shadowNode, nullptr, {/* .includeTransform = */ true});
850
-
851
- if (layoutMetrics == EmptyLayoutMetrics) {
852
- // Originally, in this case React Native returns `{0, 0, 0, 0, 0, 0}`,
853
- // most likely due to the type of measure callback function which accepts
854
- // just an array of numbers (not null). In Reanimated, `measure` returns
855
- // `MeasuredDimensions | null`.
856
- return jsi::Value::null();
857
- }
858
- auto newestCloneOfShadowNode =
859
- uiManager_->getNewestCloneOfShadowNode(*shadowNode);
860
-
861
- auto layoutableShadowNode =
862
- dynamic_cast<LayoutableShadowNode const *>(newestCloneOfShadowNode.get());
863
- facebook::react::Point originRelativeToParent =
864
- layoutableShadowNode != nullptr
865
- ? layoutableShadowNode->getLayoutMetrics().frame.origin
866
- : facebook::react::Point();
867
-
868
- auto frame = layoutMetrics.frame;
869
-
870
- jsi::Object result(rt);
871
- result.setProperty(
872
- rt, "x", jsi::Value(static_cast<double>(originRelativeToParent.x)));
873
- result.setProperty(
874
- rt, "y", jsi::Value(static_cast<double>(originRelativeToParent.y)));
875
- result.setProperty(
876
- rt, "width", jsi::Value(static_cast<double>(frame.size.width)));
877
- result.setProperty(
878
- rt, "height", jsi::Value(static_cast<double>(frame.size.height)));
879
- result.setProperty(
880
- rt, "pageX", jsi::Value(static_cast<double>(frame.origin.x)));
881
- result.setProperty(
882
- rt, "pageY", jsi::Value(static_cast<double>(frame.origin.y)));
883
- return result;
884
- }
885
-
886
- void ReanimatedModuleProxy::initializeFabric(
887
- const std::shared_ptr<UIManager> &uiManager) {
888
- uiManager_ = uiManager;
889
-
890
- initializeLayoutAnimationsProxy();
891
-
892
- mountHook_ =
893
- std::make_shared<ReanimatedMountHook>(propsRegistry_, uiManager_);
894
- commitHook_ = std::make_shared<ReanimatedCommitHook>(
895
- propsRegistry_, uiManager_, layoutAnimationsProxy_);
896
- }
897
-
898
- void ReanimatedModuleProxy::initializeLayoutAnimationsProxy() {
899
- uiManager_->setAnimationDelegate(nullptr);
900
- auto scheduler = reinterpret_cast<Scheduler *>(uiManager_->getDelegate());
901
- auto componentDescriptorRegistry =
902
- scheduler->getContextContainer()
903
- ->at<std::weak_ptr<const ComponentDescriptorRegistry>>(
904
- "ComponentDescriptorRegistry_DO_NOT_USE_PRETTY_PLEASE")
905
- .lock();
906
-
907
- if (componentDescriptorRegistry) {
908
- layoutAnimationsProxy_ = std::make_shared<LayoutAnimationsProxy>(
909
- layoutAnimationsManager_,
910
- componentDescriptorRegistry,
911
- scheduler->getContextContainer(),
912
- uiWorkletRuntime_->getJSIRuntime(),
913
- workletsModuleProxy_->getUIScheduler());
914
- }
915
- }
916
-
917
- #ifdef IS_REANIMATED_EXAMPLE_APP
918
-
919
- std::string format(bool b) {
920
- return b ? "✅" : "❌";
921
- }
922
-
923
- std::function<std::string()>
924
- ReanimatedModuleProxy::createRegistriesLeakCheck() {
925
- return [weakThis = weak_from_this()]() {
926
- auto strongThis = weakThis.lock();
927
- if (!strongThis) {
928
- return std::string("");
929
- }
930
-
931
- std::string result = "";
932
-
933
- result += "PropsRegistry: " + format(strongThis->propsRegistry_->isEmpty());
934
-
935
- return result;
936
- };
937
- }
938
-
939
- #endif // IS_REANIMATED_EXAMPLE_APP
940
-
941
- #endif // RCT_NEW_ARCH_ENABLED
942
-
943
- jsi::Value ReanimatedModuleProxy::subscribeForKeyboardEvents(
944
- jsi::Runtime &rt,
945
- const jsi::Value &handlerWorklet,
946
- const jsi::Value &isStatusBarTranslucent,
947
- const jsi::Value &isNavigationBarTranslucent) {
948
- auto shareableHandler = extractShareableOrThrow<ShareableWorklet>(
949
- rt,
950
- handlerWorklet,
951
- "[Reanimated] Keyboard event handler must be a worklet.");
952
- return subscribeForKeyboardEventsFunction_(
953
- [=, weakThis = weak_from_this()](int keyboardState, int height) {
954
- auto strongThis = weakThis.lock();
955
- if (!strongThis) {
956
- return;
957
- }
958
- strongThis->uiWorkletRuntime_->runGuarded(
959
- shareableHandler, jsi::Value(keyboardState), jsi::Value(height));
960
- },
961
- isStatusBarTranslucent.getBool(),
962
- isNavigationBarTranslucent.getBool());
963
- }
964
-
965
- void ReanimatedModuleProxy::unsubscribeFromKeyboardEvents(
966
- jsi::Runtime &,
967
- const jsi::Value &listenerId) {
968
- unsubscribeFromKeyboardEventsFunction_(listenerId.asNumber());
969
- }
970
-
971
- } // namespace reanimated
1
+ #include <jsi/jsi.h>
2
+ #include <reanimated/NativeModules/ReanimatedModuleProxy.h>
3
+ #include <reanimated/RuntimeDecorators/UIRuntimeDecorator.h>
4
+ #include <reanimated/Tools/CollectionUtils.h>
5
+ #include <reanimated/Tools/FeaturesConfig.h>
6
+ #include <reanimated/Tools/ReanimatedSystraceSection.h>
7
+ #include <unordered_map>
8
+
9
+ #ifdef RCT_NEW_ARCH_ENABLED
10
+ #include <reanimated/Fabric/ReanimatedCommitShadowNode.h>
11
+ #include <reanimated/Fabric/ShadowTreeCloner.h>
12
+ #endif // RCT_NEW_ARCH_ENABLED
13
+
14
+ #include <worklets/Registries/EventHandlerRegistry.h>
15
+ #include <worklets/SharedItems/Shareables.h>
16
+ #include <worklets/Tools/AsyncQueue.h>
17
+ #include <worklets/Tools/WorkletEventHandler.h>
18
+
19
+ #ifdef __ANDROID__
20
+ #include <fbjni/fbjni.h>
21
+ #endif // __ANDROID__
22
+
23
+ #ifdef RCT_NEW_ARCH_ENABLED
24
+ #include <react/renderer/scheduler/Scheduler.h>
25
+ #include <react/renderer/uimanager/UIManagerBinding.h>
26
+ #include <react/renderer/uimanager/primitives.h>
27
+ #endif // RCT_NEW_ARCH_ENABLED
28
+
29
+ #include <functional>
30
+ #include <utility>
31
+
32
+ #ifdef RCT_NEW_ARCH_ENABLED
33
+ #include <iomanip>
34
+ #include <sstream>
35
+ #include <string>
36
+ #endif // RCT_NEW_ARCH_ENABLED
37
+
38
+ namespace reanimated {
39
+
40
+ ReanimatedModuleProxy::ReanimatedModuleProxy(
41
+ const std::shared_ptr<WorkletsModuleProxy> &workletsModuleProxy,
42
+ jsi::Runtime &rnRuntime,
43
+ const std::shared_ptr<CallInvoker> &jsCallInvoker,
44
+ const PlatformDepMethodsHolder &platformDepMethodsHolder,
45
+ const bool isBridgeless,
46
+ const bool isReducedMotion)
47
+ : ReanimatedModuleProxySpec(jsCallInvoker),
48
+ isBridgeless_(isBridgeless),
49
+ isReducedMotion_(isReducedMotion),
50
+ workletsModuleProxy_(workletsModuleProxy),
51
+ valueUnpackerCode_(workletsModuleProxy->getValueUnpackerCode()),
52
+ uiWorkletRuntime_(std::make_shared<WorkletRuntime>(
53
+ rnRuntime,
54
+ workletsModuleProxy->getJSQueue(),
55
+ workletsModuleProxy->getJSScheduler(),
56
+ "Reanimated UI runtime",
57
+ true /* supportsLocking */,
58
+ valueUnpackerCode_)),
59
+ eventHandlerRegistry_(std::make_unique<EventHandlerRegistry>()),
60
+ requestRender_(platformDepMethodsHolder.requestRender),
61
+ animatedSensorModule_(platformDepMethodsHolder),
62
+ jsLogger_(
63
+ std::make_shared<JSLogger>(workletsModuleProxy->getJSScheduler())),
64
+ layoutAnimationsManager_(
65
+ std::make_shared<LayoutAnimationsManager>(jsLogger_)),
66
+ #ifdef RCT_NEW_ARCH_ENABLED
67
+ propsRegistry_(std::make_shared<PropsRegistry>()),
68
+ #else
69
+ obtainPropFunction_(platformDepMethodsHolder.obtainPropFunction),
70
+ configurePropsPlatformFunction_(
71
+ platformDepMethodsHolder.configurePropsFunction),
72
+ updatePropsFunction_(platformDepMethodsHolder.updatePropsFunction),
73
+ #endif
74
+ subscribeForKeyboardEventsFunction_(
75
+ platformDepMethodsHolder.subscribeForKeyboardEvents),
76
+ unsubscribeFromKeyboardEventsFunction_(
77
+ platformDepMethodsHolder.unsubscribeFromKeyboardEvents) {
78
+ }
79
+
80
+ void ReanimatedModuleProxy::init(
81
+ const PlatformDepMethodsHolder &platformDepMethodsHolder) {
82
+ auto onRenderCallback = [weakThis =
83
+ weak_from_this()](const double timestampMs) {
84
+ auto strongThis = weakThis.lock();
85
+ if (!strongThis) {
86
+ return;
87
+ }
88
+
89
+ strongThis->renderRequested_ = false;
90
+ strongThis->onRender(timestampMs);
91
+ };
92
+ onRenderCallback_ = std::move(onRenderCallback);
93
+
94
+ auto requestAnimationFrame = [weakThis = weak_from_this()](
95
+ jsi::Runtime &rt,
96
+ const jsi::Value &callback) {
97
+ auto strongThis = weakThis.lock();
98
+ if (!strongThis) {
99
+ return;
100
+ }
101
+
102
+ strongThis->requestAnimationFrame(rt, callback);
103
+ };
104
+
105
+ #ifdef RCT_NEW_ARCH_ENABLED
106
+ auto updateProps = [weakThis = weak_from_this()](
107
+ jsi::Runtime &rt, const jsi::Value &operations) {
108
+ auto strongThis = weakThis.lock();
109
+ if (!strongThis) {
110
+ return;
111
+ }
112
+
113
+ strongThis->updateProps(rt, operations);
114
+ };
115
+
116
+ auto removeFromPropsRegistry = [weakThis = weak_from_this()](
117
+ jsi::Runtime &rt,
118
+ const jsi::Value &viewTags) {
119
+ auto strongThis = weakThis.lock();
120
+ if (!strongThis) {
121
+ return;
122
+ }
123
+
124
+ strongThis->removeFromPropsRegistry(rt, viewTags);
125
+ };
126
+
127
+ auto measure = [weakThis = weak_from_this()](
128
+ jsi::Runtime &rt,
129
+ const jsi::Value &shadowNodeValue) -> jsi::Value {
130
+ auto strongThis = weakThis.lock();
131
+ if (!strongThis) {
132
+ return jsi::Value::undefined();
133
+ }
134
+ return strongThis->measure(rt, shadowNodeValue);
135
+ };
136
+
137
+ auto dispatchCommand = [weakThis = weak_from_this()](
138
+ jsi::Runtime &rt,
139
+ const jsi::Value &shadowNodeValue,
140
+ const jsi::Value &commandNameValue,
141
+ const jsi::Value &argsValue) {
142
+ auto strongThis = weakThis.lock();
143
+ if (!strongThis) {
144
+ return;
145
+ }
146
+
147
+ strongThis->dispatchCommand(
148
+ rt, shadowNodeValue, commandNameValue, argsValue);
149
+ };
150
+ ProgressLayoutAnimationFunction progressLayoutAnimation =
151
+ [weakThis = weak_from_this()](
152
+ jsi::Runtime &rt, int tag, const jsi::Object &newStyle, bool) {
153
+ auto strongThis = weakThis.lock();
154
+ if (!strongThis) {
155
+ return;
156
+ }
157
+
158
+ auto surfaceId =
159
+ strongThis->layoutAnimationsProxy_->progressLayoutAnimation(
160
+ tag, newStyle);
161
+ if (!surfaceId) {
162
+ return;
163
+ }
164
+ strongThis->uiManager_->getShadowTreeRegistry().visit(
165
+ *surfaceId, [](const ShadowTree &shadowTree) {
166
+ shadowTree.notifyDelegatesOfUpdates();
167
+ });
168
+ };
169
+
170
+ EndLayoutAnimationFunction endLayoutAnimation =
171
+ [weakThis = weak_from_this()](int tag, bool shouldRemove) {
172
+ auto strongThis = weakThis.lock();
173
+ if (!strongThis) {
174
+ return;
175
+ }
176
+
177
+ auto surfaceId = strongThis->layoutAnimationsProxy_->endLayoutAnimation(
178
+ tag, shouldRemove);
179
+ if (!surfaceId) {
180
+ return;
181
+ }
182
+
183
+ strongThis->uiManager_->getShadowTreeRegistry().visit(
184
+ *surfaceId, [](const ShadowTree &shadowTree) {
185
+ shadowTree.notifyDelegatesOfUpdates();
186
+ });
187
+ };
188
+
189
+ auto obtainProp = [weakThis = weak_from_this()](
190
+ jsi::Runtime &rt,
191
+ const jsi::Value &shadowNodeWrapper,
192
+ const jsi::Value &propName) {
193
+ auto strongThis = weakThis.lock();
194
+ if (!strongThis) {
195
+ return jsi::String::createFromUtf8(rt, "");
196
+ }
197
+
198
+ return strongThis->obtainProp(rt, shadowNodeWrapper, propName);
199
+ };
200
+ #endif
201
+
202
+ jsi::Runtime &uiRuntime = uiWorkletRuntime_->getJSIRuntime();
203
+ UIRuntimeDecorator::decorate(
204
+ uiRuntime,
205
+ #ifdef RCT_NEW_ARCH_ENABLED
206
+ obtainProp,
207
+ updateProps,
208
+ measure,
209
+ dispatchCommand,
210
+ #else
211
+ platformDepMethodsHolder.scrollToFunction,
212
+ platformDepMethodsHolder.obtainPropFunction,
213
+ platformDepMethodsHolder.updatePropsFunction,
214
+ platformDepMethodsHolder.measureFunction,
215
+ platformDepMethodsHolder.dispatchCommandFunction,
216
+ #endif
217
+ requestAnimationFrame,
218
+ platformDepMethodsHolder.getAnimationTimestamp,
219
+ platformDepMethodsHolder.setGestureStateFunction,
220
+ #ifdef RCT_NEW_ARCH_ENABLED
221
+ progressLayoutAnimation,
222
+ endLayoutAnimation,
223
+ #else
224
+ platformDepMethodsHolder.progressLayoutAnimation,
225
+ platformDepMethodsHolder.endLayoutAnimation,
226
+ #endif
227
+ platformDepMethodsHolder.maybeFlushUIUpdatesQueueFunction);
228
+ }
229
+
230
+ ReanimatedModuleProxy::~ReanimatedModuleProxy() {
231
+ // event handler registry and frame callbacks store some JSI values from UI
232
+ // runtime, so they have to go away before we tear down the runtime
233
+ eventHandlerRegistry_.reset();
234
+ frameCallbacks_.clear();
235
+ #ifdef RCT_NEW_ARCH_ENABLED
236
+ operationsInBatch_.clear();
237
+ #endif // RCT_NEW_ARCH_ENABLED
238
+ uiWorkletRuntime_.reset();
239
+ }
240
+
241
+ void ReanimatedModuleProxy::scheduleOnUI(
242
+ jsi::Runtime &rt,
243
+ const jsi::Value &worklet) {
244
+ auto shareableWorklet = extractShareableOrThrow<ShareableWorklet>(
245
+ rt, worklet, "[Reanimated] Only worklets can be scheduled to run on UI.");
246
+ workletsModuleProxy_->getUIScheduler()->scheduleOnUI(
247
+ [=, weakThis = weak_from_this()] {
248
+ const auto strongThis = weakThis.lock();
249
+ if (!strongThis) {
250
+ return;
251
+ }
252
+ #if JS_RUNTIME_HERMES
253
+ // JSI's scope defined here allows for JSI-objects to be cleared up
254
+ // after each runtime loop. Within these loops we typically create some
255
+ // temporary JSI objects and hence it allows for such objects to be
256
+ // garbage collected much sooner. Apparently the scope API is only
257
+ // supported on Hermes at the moment.
258
+ const auto scope =
259
+ jsi::Scope(strongThis->uiWorkletRuntime_->getJSIRuntime());
260
+ #endif
261
+ strongThis->uiWorkletRuntime_->runGuarded(shareableWorklet);
262
+ });
263
+ }
264
+
265
+ jsi::Value ReanimatedModuleProxy::executeOnUIRuntimeSync(
266
+ jsi::Runtime &rt,
267
+ const jsi::Value &worklet) {
268
+ return uiWorkletRuntime_->executeSync(rt, worklet);
269
+ }
270
+
271
+ jsi::Value ReanimatedModuleProxy::createWorkletRuntime(
272
+ jsi::Runtime &rt,
273
+ const jsi::Value &name,
274
+ const jsi::Value &initializer) {
275
+ auto workletRuntime = std::make_shared<WorkletRuntime>(
276
+ rt,
277
+ workletsModuleProxy_->getJSQueue(),
278
+ workletsModuleProxy_->getJSScheduler(),
279
+ name.asString(rt).utf8(rt),
280
+ true /* supportsLocking */,
281
+ valueUnpackerCode_);
282
+ auto initializerShareable = extractShareableOrThrow<ShareableWorklet>(
283
+ rt, initializer, "[Reanimated] Initializer must be a worklet.");
284
+ workletRuntime->runGuarded(initializerShareable);
285
+ return jsi::Object::createFromHostObject(rt, workletRuntime);
286
+ }
287
+
288
+ jsi::Value ReanimatedModuleProxy::scheduleOnRuntime(
289
+ jsi::Runtime &rt,
290
+ const jsi::Value &workletRuntimeValue,
291
+ const jsi::Value &shareableWorkletValue) {
292
+ reanimated::scheduleOnRuntime(rt, workletRuntimeValue, shareableWorkletValue);
293
+ return jsi::Value::undefined();
294
+ }
295
+
296
+ jsi::Value ReanimatedModuleProxy::registerEventHandler(
297
+ jsi::Runtime &rt,
298
+ const jsi::Value &worklet,
299
+ const jsi::Value &eventName,
300
+ const jsi::Value &emitterReactTag) {
301
+ static uint64_t NEXT_EVENT_HANDLER_ID = 1;
302
+
303
+ uint64_t newRegistrationId = NEXT_EVENT_HANDLER_ID++;
304
+ auto eventNameStr = eventName.asString(rt).utf8(rt);
305
+ auto handlerShareable = extractShareableOrThrow<ShareableWorklet>(
306
+ rt, worklet, "[Reanimated] Event handler must be a worklet.");
307
+ int emitterReactTagInt = emitterReactTag.asNumber();
308
+
309
+ workletsModuleProxy_->getUIScheduler()->scheduleOnUI(
310
+ [=, weakThis = weak_from_this()]() {
311
+ auto strongThis = weakThis.lock();
312
+ if (!strongThis) {
313
+ return;
314
+ }
315
+ auto handler = std::make_shared<WorkletEventHandler>(
316
+ newRegistrationId,
317
+ eventNameStr,
318
+ emitterReactTagInt,
319
+ handlerShareable);
320
+ strongThis->eventHandlerRegistry_->registerEventHandler(
321
+ std::move(handler));
322
+ });
323
+
324
+ return jsi::Value(static_cast<double>(newRegistrationId));
325
+ }
326
+
327
+ void ReanimatedModuleProxy::unregisterEventHandler(
328
+ jsi::Runtime &,
329
+ const jsi::Value &registrationId) {
330
+ uint64_t id = registrationId.asNumber();
331
+ workletsModuleProxy_->getUIScheduler()->scheduleOnUI(
332
+ [=, weakThis = weak_from_this()]() {
333
+ auto strongThis = weakThis.lock();
334
+ if (!strongThis) {
335
+ return;
336
+ }
337
+ strongThis->eventHandlerRegistry_->unregisterEventHandler(id);
338
+ });
339
+ }
340
+
341
+ #ifdef RCT_NEW_ARCH_ENABLED
342
+ static inline std::string intColorToHex(const int val) {
343
+ std::stringstream
344
+ invertedHexColorStream; // By default transparency is first, color second
345
+ invertedHexColorStream << std::setfill('0') << std::setw(8) << std::hex
346
+ << val;
347
+
348
+ auto invertedHexColor = invertedHexColorStream.str();
349
+ auto hexColor =
350
+ "#" + invertedHexColor.substr(2, 6) + invertedHexColor.substr(0, 2);
351
+
352
+ return hexColor;
353
+ }
354
+
355
+ std::string ReanimatedModuleProxy::obtainPropFromShadowNode(
356
+ jsi::Runtime &rt,
357
+ const std::string &propName,
358
+ const ShadowNode::Shared &shadowNode) {
359
+ auto newestCloneOfShadowNode =
360
+ uiManager_->getNewestCloneOfShadowNode(*shadowNode);
361
+
362
+ if (propName == "width" || propName == "height" || propName == "top" ||
363
+ propName == "left") {
364
+ // These props are calculated from frame
365
+ auto layoutableShadowNode = dynamic_cast<LayoutableShadowNode const *>(
366
+ newestCloneOfShadowNode.get());
367
+ const auto &frame = layoutableShadowNode->layoutMetrics_.frame;
368
+
369
+ if (propName == "width") {
370
+ return std::to_string(frame.size.width);
371
+ } else if (propName == "height") {
372
+ return std::to_string(frame.size.height);
373
+ } else if (propName == "top") {
374
+ return std::to_string(frame.origin.y);
375
+ } else if (propName == "left") {
376
+ return std::to_string(frame.origin.x);
377
+ }
378
+ } else {
379
+ // These props are calculated from viewProps
380
+ auto props = newestCloneOfShadowNode->getProps();
381
+ auto viewProps = std::static_pointer_cast<const ViewProps>(props);
382
+ if (propName == "opacity") {
383
+ return std::to_string(viewProps->opacity);
384
+ } else if (propName == "zIndex") {
385
+ if (viewProps->zIndex.has_value()) {
386
+ return std::to_string(*viewProps->zIndex);
387
+ }
388
+ } else if (propName == "backgroundColor") {
389
+ return intColorToHex(*viewProps->backgroundColor);
390
+ }
391
+ }
392
+
393
+ throw std::runtime_error(std::string(
394
+ "Getting property `" + propName +
395
+ "` with function `getViewProp` is not supported"));
396
+ }
397
+
398
+ jsi::Value ReanimatedModuleProxy::getViewProp(
399
+ jsi::Runtime &rnRuntime,
400
+ const jsi::Value &shadowNodeWrapper,
401
+ const jsi::Value &propName,
402
+ const jsi::Value &callback) {
403
+ const auto propNameStr = propName.asString(rnRuntime).utf8(rnRuntime);
404
+ const auto funPtr = std::make_shared<jsi::Function>(
405
+ callback.getObject(rnRuntime).asFunction(rnRuntime));
406
+ const auto shadowNode = shadowNodeFromValue(rnRuntime, shadowNodeWrapper);
407
+ workletsModuleProxy_->getUIScheduler()->scheduleOnUI(
408
+ [=, weakThis = weak_from_this()]() {
409
+ auto strongThis = weakThis.lock();
410
+ if (!strongThis) {
411
+ return;
412
+ }
413
+ jsi::Runtime &uiRuntime =
414
+ strongThis->uiWorkletRuntime_->getJSIRuntime();
415
+ const auto resultStr = strongThis->obtainPropFromShadowNode(
416
+ uiRuntime, propNameStr, shadowNode);
417
+
418
+ strongThis->workletsModuleProxy_->getJSScheduler()->scheduleOnJS(
419
+ [=](jsi::Runtime &rnRuntime) {
420
+ const auto resultValue =
421
+ jsi::String::createFromUtf8(rnRuntime, resultStr);
422
+ funPtr->call(rnRuntime, resultValue);
423
+ });
424
+ });
425
+ return jsi::Value::undefined();
426
+ }
427
+
428
+ #else
429
+
430
+ jsi::Value ReanimatedModuleProxy::getViewProp(
431
+ jsi::Runtime &rnRuntime,
432
+ const jsi::Value &viewTag,
433
+ const jsi::Value &propName,
434
+ const jsi::Value &callback) {
435
+ const auto propNameStr = propName.asString(rnRuntime).utf8(rnRuntime);
436
+ const auto funPtr = std::make_shared<jsi::Function>(
437
+ callback.getObject(rnRuntime).asFunction(rnRuntime));
438
+
439
+ const int viewTagInt = viewTag.asNumber();
440
+
441
+ workletsModuleProxy_->getUIScheduler()->scheduleOnUI(
442
+ [=, weakThis = weak_from_this()]
443
+
444
+ () {
445
+ auto strongThis = weakThis.lock();
446
+ if (!strongThis) {
447
+ return;
448
+ }
449
+ jsi::Runtime &uiRuntime =
450
+ strongThis->uiWorkletRuntime_->getJSIRuntime();
451
+ const jsi::Value propNameValue =
452
+ jsi::String::createFromUtf8(uiRuntime, propNameStr);
453
+ const auto resultValue = strongThis->obtainPropFunction_(
454
+ uiRuntime, viewTagInt, propNameValue);
455
+ const auto resultStr = resultValue.asString(uiRuntime).utf8(uiRuntime);
456
+ const auto jsScheduler =
457
+ strongThis->workletsModuleProxy_->getJSScheduler();
458
+ jsScheduler->scheduleOnJS([=](jsi::Runtime &rnRuntime) {
459
+ const auto resultValue =
460
+ jsi::String::createFromUtf8(rnRuntime, resultStr);
461
+ funPtr->call(rnRuntime, resultValue);
462
+ });
463
+ });
464
+ return jsi::Value::undefined();
465
+ }
466
+
467
+ #endif
468
+
469
+ jsi::Value ReanimatedModuleProxy::enableLayoutAnimations(
470
+ jsi::Runtime &,
471
+ const jsi::Value &config) {
472
+ FeaturesConfig::setLayoutAnimationEnabled(config.getBool());
473
+ return jsi::Value::undefined();
474
+ }
475
+
476
+ jsi::Value ReanimatedModuleProxy::configureProps(
477
+ jsi::Runtime &rt,
478
+ const jsi::Value &uiProps,
479
+ const jsi::Value &nativeProps) {
480
+ #ifdef RCT_NEW_ARCH_ENABLED
481
+ auto uiPropsArray = uiProps.asObject(rt).asArray(rt);
482
+ for (size_t i = 0; i < uiPropsArray.size(rt); ++i) {
483
+ auto name = uiPropsArray.getValueAtIndex(rt, i).asString(rt).utf8(rt);
484
+ animatablePropNames_.insert(name);
485
+ }
486
+ auto nativePropsArray = nativeProps.asObject(rt).asArray(rt);
487
+ for (size_t i = 0; i < nativePropsArray.size(rt); ++i) {
488
+ auto name = nativePropsArray.getValueAtIndex(rt, i).asString(rt).utf8(rt);
489
+ animatablePropNames_.insert(name);
490
+ }
491
+ #else
492
+ configurePropsPlatformFunction_(rt, uiProps, nativeProps);
493
+ #endif // RCT_NEW_ARCH_ENABLED
494
+
495
+ return jsi::Value::undefined();
496
+ }
497
+
498
+ jsi::Value ReanimatedModuleProxy::configureLayoutAnimationBatch(
499
+ jsi::Runtime &rt,
500
+ const jsi::Value &layoutAnimationsBatch) {
501
+ auto array = layoutAnimationsBatch.asObject(rt).asArray(rt);
502
+ size_t length = array.size(rt);
503
+ std::vector<LayoutAnimationConfig> batch(length);
504
+ for (int i = 0; i < length; i++) {
505
+ auto item = array.getValueAtIndex(rt, i).asObject(rt);
506
+ auto &batchItem = batch[i];
507
+ batchItem.tag = item.getProperty(rt, "viewTag").asNumber();
508
+ batchItem.type = static_cast<LayoutAnimationType>(
509
+ item.getProperty(rt, "type").asNumber());
510
+ auto config = item.getProperty(rt, "config");
511
+ if (config.isUndefined()) {
512
+ batchItem.config = nullptr;
513
+ } else {
514
+ batchItem.config = extractShareableOrThrow<ShareableObject>(
515
+ rt,
516
+ config,
517
+ "[Reanimated] Layout animation config must be an object.");
518
+ }
519
+ if (batch[i].type != SHARED_ELEMENT_TRANSITION &&
520
+ batch[i].type != SHARED_ELEMENT_TRANSITION_PROGRESS) {
521
+ continue;
522
+ }
523
+ auto sharedTransitionTag = item.getProperty(rt, "sharedTransitionTag");
524
+ if (sharedTransitionTag.isUndefined()) {
525
+ batch[i].config = nullptr;
526
+ } else {
527
+ batch[i].sharedTransitionTag = sharedTransitionTag.asString(rt).utf8(rt);
528
+ }
529
+ }
530
+ layoutAnimationsManager_->configureAnimationBatch(batch);
531
+ return jsi::Value::undefined();
532
+ }
533
+
534
+ void ReanimatedModuleProxy::setShouldAnimateExiting(
535
+ jsi::Runtime &rt,
536
+ const jsi::Value &viewTag,
537
+ const jsi::Value &shouldAnimate) {
538
+ layoutAnimationsManager_->setShouldAnimateExiting(
539
+ viewTag.asNumber(), shouldAnimate.getBool());
540
+ }
541
+
542
+ bool ReanimatedModuleProxy::isAnyHandlerWaitingForEvent(
543
+ const std::string &eventName,
544
+ const int emitterReactTag) {
545
+ return eventHandlerRegistry_->isAnyHandlerWaitingForEvent(
546
+ eventName, emitterReactTag);
547
+ }
548
+
549
+ void ReanimatedModuleProxy::requestAnimationFrame(
550
+ jsi::Runtime &rt,
551
+ const jsi::Value &callback) {
552
+ frameCallbacks_.push_back(std::make_shared<jsi::Value>(rt, callback));
553
+ maybeRequestRender();
554
+ }
555
+
556
+ void ReanimatedModuleProxy::maybeRequestRender() {
557
+ if (!renderRequested_) {
558
+ renderRequested_ = true;
559
+ requestRender_(onRenderCallback_);
560
+ }
561
+ }
562
+
563
+ void ReanimatedModuleProxy::onRender(double timestampMs) {
564
+ auto callbacks = std::move(frameCallbacks_);
565
+ frameCallbacks_.clear();
566
+ jsi::Runtime &uiRuntime = uiWorkletRuntime_->getJSIRuntime();
567
+ jsi::Value timestamp{timestampMs};
568
+ for (const auto &callback : callbacks) {
569
+ runOnRuntimeGuarded(uiRuntime, *callback, timestamp);
570
+ }
571
+ }
572
+
573
+ jsi::Value ReanimatedModuleProxy::registerSensor(
574
+ jsi::Runtime &rt,
575
+ const jsi::Value &sensorType,
576
+ const jsi::Value &interval,
577
+ const jsi::Value &iosReferenceFrame,
578
+ const jsi::Value &sensorDataHandler) {
579
+ return animatedSensorModule_.registerSensor(
580
+ rt,
581
+ uiWorkletRuntime_,
582
+ sensorType,
583
+ interval,
584
+ iosReferenceFrame,
585
+ sensorDataHandler);
586
+ }
587
+
588
+ void ReanimatedModuleProxy::unregisterSensor(
589
+ jsi::Runtime &,
590
+ const jsi::Value &sensorId) {
591
+ animatedSensorModule_.unregisterSensor(sensorId);
592
+ }
593
+
594
+ void ReanimatedModuleProxy::cleanupSensors() {
595
+ animatedSensorModule_.unregisterAllSensors();
596
+ }
597
+
598
+ #ifdef RCT_NEW_ARCH_ENABLED
599
+
600
+ void ReanimatedModuleProxy::markNodeAsRemovable(
601
+ jsi::Runtime &rt,
602
+ const jsi::Value &shadowNodeWrapper) {
603
+ auto shadowNode = shadowNodeFromValue(rt, shadowNodeWrapper);
604
+ propsRegistry_->markNodeAsRemovable(shadowNode);
605
+ }
606
+
607
+ void ReanimatedModuleProxy::unmarkNodeAsRemovable(
608
+ jsi::Runtime &rt,
609
+ const jsi::Value &viewTag) {
610
+ propsRegistry_->unmarkNodeAsRemovable(viewTag.asNumber());
611
+ }
612
+
613
+ jsi::Value ReanimatedModuleProxy::filterNonAnimatableProps(
614
+ jsi::Runtime &rt,
615
+ const jsi::Value &props) {
616
+ jsi::Object nonAnimatableProps(rt);
617
+ bool hasAnyNonAnimatableProp = false;
618
+ const jsi::Object &propsObject = props.asObject(rt);
619
+ const jsi::Array &propNames = propsObject.getPropertyNames(rt);
620
+ for (size_t i = 0; i < propNames.size(rt); ++i) {
621
+ const std::string &propName =
622
+ propNames.getValueAtIndex(rt, i).asString(rt).utf8(rt);
623
+ if (!collection::contains(animatablePropNames_, propName)) {
624
+ hasAnyNonAnimatableProp = true;
625
+ const auto &propNameStr = propName.c_str();
626
+ const jsi::Value &propValue = propsObject.getProperty(rt, propNameStr);
627
+ nonAnimatableProps.setProperty(rt, propNameStr, propValue);
628
+ }
629
+ }
630
+ if (!hasAnyNonAnimatableProp) {
631
+ return jsi::Value::undefined();
632
+ }
633
+ return nonAnimatableProps;
634
+ }
635
+ #endif // RCT_NEW_ARCH_ENABLED
636
+
637
+ bool ReanimatedModuleProxy::handleEvent(
638
+ const std::string &eventName,
639
+ const int emitterReactTag,
640
+ const jsi::Value &payload,
641
+ double currentTime) {
642
+ eventHandlerRegistry_->processEvent(
643
+ uiWorkletRuntime_, currentTime, eventName, emitterReactTag, payload);
644
+
645
+ // TODO: return true if Reanimated successfully handled the event
646
+ // to avoid sending it to JavaScript
647
+ return false;
648
+ }
649
+
650
+ #ifdef RCT_NEW_ARCH_ENABLED
651
+ bool ReanimatedModuleProxy::handleRawEvent(
652
+ const RawEvent &rawEvent,
653
+ double currentTime) {
654
+ const EventTarget *eventTarget = rawEvent.eventTarget.get();
655
+ if (eventTarget == nullptr) {
656
+ // after app reload scrollView is unmounted and its content offset is set
657
+ // to 0 and view is thrown into recycle pool setting content offset
658
+ // triggers scroll event eventTarget is null though, because it's
659
+ // unmounting we can just ignore this event, because it's an event on
660
+ // unmounted component
661
+ return false;
662
+ }
663
+
664
+ int tag = eventTarget->getTag();
665
+ auto eventType = rawEvent.type;
666
+ if (eventType.rfind("top", 0) == 0) {
667
+ eventType = "on" + eventType.substr(3);
668
+ }
669
+ jsi::Runtime &rt = uiWorkletRuntime_->getJSIRuntime();
670
+
671
+ if (!isAnyHandlerWaitingForEvent(eventType, tag)) {
672
+ return false;
673
+ }
674
+
675
+ const auto &eventPayload = rawEvent.eventPayload;
676
+ jsi::Value payload = eventPayload->asJSIValue(rt);
677
+
678
+ auto res = handleEvent(eventType, tag, std::move(payload), currentTime);
679
+ // TODO: we should call performOperations conditionally if event is handled
680
+ // (res == true), but for now handleEvent always returns false. Thankfully,
681
+ // performOperations does not trigger a lot of code if there is nothing to
682
+ // be done so this is fine for now.
683
+ performOperations();
684
+ return res;
685
+ }
686
+
687
+ void ReanimatedModuleProxy::updateProps(
688
+ jsi::Runtime &rt,
689
+ const jsi::Value &operations) {
690
+ auto array = operations.asObject(rt).asArray(rt);
691
+ size_t length = array.size(rt);
692
+ for (size_t i = 0; i < length; ++i) {
693
+ auto item = array.getValueAtIndex(rt, i).asObject(rt);
694
+ auto shadowNodeWrapper = item.getProperty(rt, "shadowNodeWrapper");
695
+ auto shadowNode = shadowNodeFromValue(rt, shadowNodeWrapper);
696
+ const jsi::Value &updates = item.getProperty(rt, "updates");
697
+ operationsInBatch_.emplace_back(
698
+ shadowNode, std::make_unique<jsi::Value>(rt, updates));
699
+ }
700
+ }
701
+
702
+ void ReanimatedModuleProxy::performOperations() {
703
+ if (operationsInBatch_.empty() && tagsToRemove_.empty()) {
704
+ // nothing to do
705
+ return;
706
+ }
707
+
708
+ ReanimatedSystraceSection s("performOperations");
709
+
710
+ auto copiedOperationsQueue = std::move(operationsInBatch_);
711
+ operationsInBatch_.clear();
712
+
713
+ jsi::Runtime &rt = uiWorkletRuntime_->getJSIRuntime();
714
+
715
+ {
716
+ auto lock = propsRegistry_->createLock();
717
+
718
+ if (copiedOperationsQueue.size() > 0 &&
719
+ propsRegistry_->shouldReanimatedSkipCommit()) {
720
+ propsRegistry_->pleaseCommitAfterPause();
721
+ }
722
+
723
+ // remove recently unmounted ShadowNodes from PropsRegistry
724
+ if (!tagsToRemove_.empty()) {
725
+ for (auto tag : tagsToRemove_) {
726
+ propsRegistry_->remove(tag);
727
+ }
728
+ tagsToRemove_.clear();
729
+ }
730
+
731
+ // Even if only non-layout props are changed, we need to store the update
732
+ // in PropsRegistry anyway so that React doesn't overwrite it in the next
733
+ // render. Currently, only opacity and transform are treated in a special
734
+ // way but backgroundColor, shadowOpacity etc. would get overwritten (see
735
+ // `_propKeysManagedByAnimated_DO_NOT_USE_THIS_IS_BROKEN`).
736
+ for (const auto &[shadowNode, props] : copiedOperationsQueue) {
737
+ propsRegistry_->update(shadowNode, dynamicFromValue(rt, *props));
738
+ }
739
+ }
740
+
741
+ for (const auto &[shadowNode, props] : copiedOperationsQueue) {
742
+ const jsi::Value &nonAnimatableProps = filterNonAnimatableProps(rt, *props);
743
+ if (nonAnimatableProps.isUndefined()) {
744
+ continue;
745
+ }
746
+ Tag viewTag = shadowNode->getTag();
747
+ jsi::Value maybeJSPropsUpdater =
748
+ rt.global().getProperty(rt, "updateJSProps");
749
+ assert(
750
+ maybeJSPropsUpdater.isObject() &&
751
+ "[Reanimated] `updateJSProps` not found");
752
+ jsi::Function jsPropsUpdater =
753
+ maybeJSPropsUpdater.asObject(rt).asFunction(rt);
754
+ jsPropsUpdater.call(rt, viewTag, nonAnimatableProps);
755
+ }
756
+
757
+ if (propsRegistry_->shouldReanimatedSkipCommit()) {
758
+ // It may happen that `performOperations` is called on the UI thread
759
+ // while React Native tries to commit a new tree on the JS thread.
760
+ // In this case, we should skip the commit here and let React Native do
761
+ // it. The commit will include the current values from PropsRegistry which
762
+ // will be applied in ReanimatedCommitHook.
763
+ return;
764
+ }
765
+
766
+ react_native_assert(uiManager_ != nullptr);
767
+ const auto &shadowTreeRegistry = uiManager_->getShadowTreeRegistry();
768
+
769
+ std::unordered_map<SurfaceId, PropsMap> propsMapBySurface;
770
+
771
+ for (auto const &[shadowNode, props] : copiedOperationsQueue) {
772
+ SurfaceId surfaceId = shadowNode->getSurfaceId();
773
+ auto family = &shadowNode->getFamily();
774
+ react_native_assert(family->getSurfaceId() == surfaceId);
775
+ propsMapBySurface[surfaceId][family].emplace_back(rt, std::move(*props));
776
+ }
777
+
778
+ for (auto const &[surfaceId, propsMap] : propsMapBySurface) {
779
+ shadowTreeRegistry.visit(surfaceId, [&](ShadowTree const &shadowTree) {
780
+ shadowTree.commit(
781
+ [&](RootShadowNode const &oldRootShadowNode)
782
+ -> RootShadowNode::Unshared {
783
+ if (propsRegistry_->shouldReanimatedSkipCommit()) {
784
+ return nullptr;
785
+ }
786
+
787
+ auto rootNode =
788
+ cloneShadowTreeWithNewProps(oldRootShadowNode, propsMap);
789
+
790
+ // Mark the commit as Reanimated commit so that we can distinguish
791
+ // it in ReanimatedCommitHook.
792
+
793
+ auto reaShadowNode =
794
+ std::reinterpret_pointer_cast<ReanimatedCommitShadowNode>(
795
+ rootNode);
796
+ reaShadowNode->setReanimatedCommitTrait();
797
+
798
+ return rootNode;
799
+ },
800
+ {/* .enableStateReconciliation = */
801
+ false,
802
+ /* .mountSynchronously = */ true});
803
+ });
804
+ }
805
+ }
806
+
807
+ void ReanimatedModuleProxy::dispatchCommand(
808
+ jsi::Runtime &rt,
809
+ const jsi::Value &shadowNodeValue,
810
+ const jsi::Value &commandNameValue,
811
+ const jsi::Value &argsValue) {
812
+ ShadowNode::Shared shadowNode = shadowNodeFromValue(rt, shadowNodeValue);
813
+ std::string commandName = stringFromValue(rt, commandNameValue);
814
+ folly::dynamic args = commandArgsFromValue(rt, argsValue);
815
+ const auto &scheduler = static_cast<Scheduler *>(uiManager_->getDelegate());
816
+
817
+ if (!scheduler) {
818
+ return;
819
+ }
820
+
821
+ const auto &schedulerDelegate = scheduler->getDelegate();
822
+
823
+ if (schedulerDelegate) {
824
+ const auto shadowView = ShadowView(*shadowNode);
825
+ schedulerDelegate->schedulerDidDispatchCommand(
826
+ shadowView, commandName, args);
827
+ }
828
+ }
829
+
830
+ jsi::String ReanimatedModuleProxy::obtainProp(
831
+ jsi::Runtime &rt,
832
+ const jsi::Value &shadowNodeWrapper,
833
+ const jsi::Value &propName) {
834
+ jsi::Runtime &uiRuntime = uiWorkletRuntime_->getJSIRuntime();
835
+ const auto propNameStr = propName.asString(rt).utf8(rt);
836
+ const auto shadowNode = shadowNodeFromValue(rt, shadowNodeWrapper);
837
+ const auto resultStr =
838
+ obtainPropFromShadowNode(uiRuntime, propNameStr, shadowNode);
839
+ return jsi::String::createFromUtf8(rt, resultStr);
840
+ }
841
+
842
+ jsi::Value ReanimatedModuleProxy::measure(
843
+ jsi::Runtime &rt,
844
+ const jsi::Value &shadowNodeValue) {
845
+ // based on implementation from UIManagerBinding.cpp
846
+
847
+ auto shadowNode = shadowNodeFromValue(rt, shadowNodeValue);
848
+ auto layoutMetrics = uiManager_->getRelativeLayoutMetrics(
849
+ *shadowNode, nullptr, {/* .includeTransform = */ true});
850
+
851
+ if (layoutMetrics == EmptyLayoutMetrics) {
852
+ // Originally, in this case React Native returns `{0, 0, 0, 0, 0, 0}`,
853
+ // most likely due to the type of measure callback function which accepts
854
+ // just an array of numbers (not null). In Reanimated, `measure` returns
855
+ // `MeasuredDimensions | null`.
856
+ return jsi::Value::null();
857
+ }
858
+ auto newestCloneOfShadowNode =
859
+ uiManager_->getNewestCloneOfShadowNode(*shadowNode);
860
+
861
+ auto layoutableShadowNode =
862
+ dynamic_cast<LayoutableShadowNode const *>(newestCloneOfShadowNode.get());
863
+ facebook::react::Point originRelativeToParent =
864
+ layoutableShadowNode != nullptr
865
+ ? layoutableShadowNode->getLayoutMetrics().frame.origin
866
+ : facebook::react::Point();
867
+
868
+ auto frame = layoutMetrics.frame;
869
+
870
+ jsi::Object result(rt);
871
+ result.setProperty(
872
+ rt, "x", jsi::Value(static_cast<double>(originRelativeToParent.x)));
873
+ result.setProperty(
874
+ rt, "y", jsi::Value(static_cast<double>(originRelativeToParent.y)));
875
+ result.setProperty(
876
+ rt, "width", jsi::Value(static_cast<double>(frame.size.width)));
877
+ result.setProperty(
878
+ rt, "height", jsi::Value(static_cast<double>(frame.size.height)));
879
+ result.setProperty(
880
+ rt, "pageX", jsi::Value(static_cast<double>(frame.origin.x)));
881
+ result.setProperty(
882
+ rt, "pageY", jsi::Value(static_cast<double>(frame.origin.y)));
883
+ return result;
884
+ }
885
+
886
+ void ReanimatedModuleProxy::initializeFabric(
887
+ const std::shared_ptr<UIManager> &uiManager) {
888
+ uiManager_ = uiManager;
889
+
890
+ initializeLayoutAnimationsProxy();
891
+
892
+ mountHook_ =
893
+ std::make_shared<ReanimatedMountHook>(propsRegistry_, uiManager_);
894
+ commitHook_ = std::make_shared<ReanimatedCommitHook>(
895
+ propsRegistry_, uiManager_, layoutAnimationsProxy_);
896
+ }
897
+
898
+ void ReanimatedModuleProxy::initializeLayoutAnimationsProxy() {
899
+ uiManager_->setAnimationDelegate(nullptr);
900
+ auto scheduler = reinterpret_cast<Scheduler *>(uiManager_->getDelegate());
901
+ auto componentDescriptorRegistry =
902
+ scheduler->getContextContainer()
903
+ ->at<std::weak_ptr<const ComponentDescriptorRegistry>>(
904
+ "ComponentDescriptorRegistry_DO_NOT_USE_PRETTY_PLEASE")
905
+ .lock();
906
+
907
+ if (componentDescriptorRegistry) {
908
+ layoutAnimationsProxy_ = std::make_shared<LayoutAnimationsProxy>(
909
+ layoutAnimationsManager_,
910
+ componentDescriptorRegistry,
911
+ scheduler->getContextContainer(),
912
+ uiWorkletRuntime_->getJSIRuntime(),
913
+ workletsModuleProxy_->getUIScheduler());
914
+ }
915
+ }
916
+
917
+ #ifdef IS_REANIMATED_EXAMPLE_APP
918
+
919
+ std::string format(bool b) {
920
+ return b ? "✅" : "❌";
921
+ }
922
+
923
+ std::function<std::string()>
924
+ ReanimatedModuleProxy::createRegistriesLeakCheck() {
925
+ return [weakThis = weak_from_this()]() {
926
+ auto strongThis = weakThis.lock();
927
+ if (!strongThis) {
928
+ return std::string("");
929
+ }
930
+
931
+ std::string result = "";
932
+
933
+ result += "PropsRegistry: " + format(strongThis->propsRegistry_->isEmpty());
934
+
935
+ return result;
936
+ };
937
+ }
938
+
939
+ #endif // IS_REANIMATED_EXAMPLE_APP
940
+
941
+ #endif // RCT_NEW_ARCH_ENABLED
942
+
943
+ jsi::Value ReanimatedModuleProxy::subscribeForKeyboardEvents(
944
+ jsi::Runtime &rt,
945
+ const jsi::Value &handlerWorklet,
946
+ const jsi::Value &isStatusBarTranslucent,
947
+ const jsi::Value &isNavigationBarTranslucent) {
948
+ auto shareableHandler = extractShareableOrThrow<ShareableWorklet>(
949
+ rt,
950
+ handlerWorklet,
951
+ "[Reanimated] Keyboard event handler must be a worklet.");
952
+ return subscribeForKeyboardEventsFunction_(
953
+ [=, weakThis = weak_from_this()](int keyboardState, int height) {
954
+ auto strongThis = weakThis.lock();
955
+ if (!strongThis) {
956
+ return;
957
+ }
958
+ strongThis->uiWorkletRuntime_->runGuarded(
959
+ shareableHandler, jsi::Value(keyboardState), jsi::Value(height));
960
+ },
961
+ isStatusBarTranslucent.getBool(),
962
+ isNavigationBarTranslucent.getBool());
963
+ }
964
+
965
+ void ReanimatedModuleProxy::unsubscribeFromKeyboardEvents(
966
+ jsi::Runtime &,
967
+ const jsi::Value &listenerId) {
968
+ unsubscribeFromKeyboardEventsFunction_(listenerId.asNumber());
969
+ }
970
+
971
+ } // namespace reanimated