1 #include "NativeReanimatedModule.h"
2 #include <functional>
3 #include <memory>
4 #include <thread>
5 #include <unordered_map>
6 #include <utility>
7
8 #include "EventHandlerRegistry.h"
9 #include "FeaturesConfig.h"
10 #include "FrozenObject.h"
11 #include "JSIStoreValueUser.h"
12 #include "Mapper.h"
13 #include "MapperRegistry.h"
14 #include "MutableValue.h"
15 #include "ReanimatedHiddenHeaders.h"
16 #include "RuntimeDecorator.h"
17 #include "ShareableValue.h"
18 #include "WorkletEventHandler.h"
19
20 using namespace facebook;
21
22 namespace reanimated {
23
extractMutables(jsi::Runtime & rt,std::shared_ptr<ShareableValue> sv,std::vector<std::shared_ptr<MutableValue>> & res)24 void extractMutables(
25 jsi::Runtime &rt,
26 std::shared_ptr<ShareableValue> sv,
27 std::vector<std::shared_ptr<MutableValue>> &res) {
28 switch (sv->type) {
29 case ValueType::MutableValueType: {
30 auto &mutableValue = ValueWrapper::asMutableValue(sv->valueContainer);
31 res.push_back(mutableValue);
32 break;
33 }
34 case ValueType::FrozenArrayType:
35 for (auto &it : ValueWrapper::asFrozenArray(sv->valueContainer)) {
36 extractMutables(rt, it, res);
37 }
38 break;
39 case ValueType::RemoteObjectType:
40 case ValueType::FrozenObjectType:
41 for (auto &it : ValueWrapper::asFrozenObject(sv->valueContainer)->map) {
42 extractMutables(rt, it.second, res);
43 }
44 break;
45 default:
46 break;
47 }
48 }
49
extractMutablesFromArray(jsi::Runtime & rt,const jsi::Array & array,NativeReanimatedModule * module)50 std::vector<std::shared_ptr<MutableValue>> extractMutablesFromArray(
51 jsi::Runtime &rt,
52 const jsi::Array &array,
53 NativeReanimatedModule *module) {
54 std::vector<std::shared_ptr<MutableValue>> res;
55 for (size_t i = 0, size = array.size(rt); i < size; i++) {
56 auto shareable =
57 ShareableValue::adapt(rt, array.getValueAtIndex(rt, i), module);
58 extractMutables(rt, shareable, res);
59 }
60 return res;
61 }
62
NativeReanimatedModule(std::shared_ptr<CallInvoker> jsInvoker,std::shared_ptr<Scheduler> scheduler,std::shared_ptr<jsi::Runtime> rt,std::shared_ptr<ErrorHandler> errorHandler,std::function<jsi::Value (jsi::Runtime &,const int,const jsi::String &)> propObtainer,std::shared_ptr<LayoutAnimationsProxy> layoutAnimationsProxy,PlatformDepMethodsHolder platformDepMethodsHolder)63 NativeReanimatedModule::NativeReanimatedModule(
64 std::shared_ptr<CallInvoker> jsInvoker,
65 std::shared_ptr<Scheduler> scheduler,
66 std::shared_ptr<jsi::Runtime> rt,
67 std::shared_ptr<ErrorHandler> errorHandler,
68 std::function<jsi::Value(jsi::Runtime &, const int, const jsi::String &)>
69 propObtainer,
70 std::shared_ptr<LayoutAnimationsProxy> layoutAnimationsProxy,
71 PlatformDepMethodsHolder platformDepMethodsHolder)
72 : NativeReanimatedModuleSpec(jsInvoker),
73 RuntimeManager(rt, errorHandler, scheduler, RuntimeType::UI),
74 mapperRegistry(std::make_shared<MapperRegistry>()),
75 eventHandlerRegistry(std::make_shared<EventHandlerRegistry>()),
76 requestRender(platformDepMethodsHolder.requestRender),
77 propObtainer(propObtainer),
78 animatedSensorModule(platformDepMethodsHolder, this),
79 configurePropsPlatformFunction(
80 platformDepMethodsHolder.configurePropsFunction) {
81 auto requestAnimationFrame = [=](FrameCallback callback) {
82 frameCallbacks.push_back(callback);
83 maybeRequestRender();
84 };
85
86 this->layoutAnimationsProxy = layoutAnimationsProxy;
87
88 RuntimeDecorator::decorateUIRuntime(
89 *runtime,
90 platformDepMethodsHolder.updaterFunction,
91 requestAnimationFrame,
92 platformDepMethodsHolder.scrollToFunction,
93 platformDepMethodsHolder.measuringFunction,
94 platformDepMethodsHolder.getCurrentTime,
95 platformDepMethodsHolder.registerSensor,
96 platformDepMethodsHolder.unregisterSensor,
97 platformDepMethodsHolder.setGestureStateFunction,
98 layoutAnimationsProxy);
99 onRenderCallback = [this](double timestampMs) {
100 this->renderRequested = false;
101 this->onRender(timestampMs);
102 };
103 updaterFunction = platformDepMethodsHolder.updaterFunction;
104 subscribeForKeyboardEventsFunction =
105 platformDepMethodsHolder.subscribeForKeyboardEvents;
106 unsubscribeFromKeyboardEventsFunction =
107 platformDepMethodsHolder.unsubscribeFromKeyboardEvents;
108 }
109
installCoreFunctions(jsi::Runtime & rt,const jsi::Value & valueSetter)110 void NativeReanimatedModule::installCoreFunctions(
111 jsi::Runtime &rt,
112 const jsi::Value &valueSetter) {
113 this->valueSetter = ShareableValue::adapt(rt, valueSetter, this);
114 }
115
makeShareable(jsi::Runtime & rt,const jsi::Value & value)116 jsi::Value NativeReanimatedModule::makeShareable(
117 jsi::Runtime &rt,
118 const jsi::Value &value) {
119 return ShareableValue::adapt(rt, value, this)->getValue(rt);
120 }
121
makeMutable(jsi::Runtime & rt,const jsi::Value & value)122 jsi::Value NativeReanimatedModule::makeMutable(
123 jsi::Runtime &rt,
124 const jsi::Value &value) {
125 return ShareableValue::adapt(rt, value, this, ValueType::MutableValueType)
126 ->getValue(rt);
127 }
128
makeRemote(jsi::Runtime & rt,const jsi::Value & value)129 jsi::Value NativeReanimatedModule::makeRemote(
130 jsi::Runtime &rt,
131 const jsi::Value &value) {
132 return ShareableValue::adapt(rt, value, this, ValueType::RemoteObjectType)
133 ->getValue(rt);
134 }
135
startMapper(jsi::Runtime & rt,const jsi::Value & worklet,const jsi::Value & inputs,const jsi::Value & outputs,const jsi::Value & updater,const jsi::Value & viewDescriptors)136 jsi::Value NativeReanimatedModule::startMapper(
137 jsi::Runtime &rt,
138 const jsi::Value &worklet,
139 const jsi::Value &inputs,
140 const jsi::Value &outputs,
141 const jsi::Value &updater,
142 const jsi::Value &viewDescriptors) {
143 static unsigned long MAPPER_ID = 1;
144
145 unsigned long newMapperId = MAPPER_ID++;
146 auto mapperShareable = ShareableValue::adapt(rt, worklet, this);
147 auto inputMutables =
148 extractMutablesFromArray(rt, inputs.asObject(rt).asArray(rt), this);
149 auto outputMutables =
150 extractMutablesFromArray(rt, outputs.asObject(rt).asArray(rt), this);
151
152 int optimalizationLvl = 0;
153 auto optimalization =
154 updater.asObject(rt).getProperty(rt, "__optimalization");
155 if (optimalization.isNumber()) {
156 optimalizationLvl = optimalization.asNumber();
157 }
158 auto updaterSV = ShareableValue::adapt(rt, updater, this);
159 auto viewDescriptorsSV = ShareableValue::adapt(rt, viewDescriptors, this);
160
161 scheduler->scheduleOnUI([=] {
162 auto mapperFunction =
163 mapperShareable->getValue(*runtime).asObject(*runtime).asFunction(
164 *runtime);
165 std::shared_ptr<jsi::Function> mapperFunctionPointer =
166 std::make_shared<jsi::Function>(std::move(mapperFunction));
167
168 std::shared_ptr<Mapper> mapperPointer = std::make_shared<Mapper>(
169 this,
170 newMapperId,
171 mapperFunctionPointer,
172 inputMutables,
173 outputMutables);
174 if (optimalizationLvl > 0) {
175 mapperPointer->enableFastMode(
176 optimalizationLvl, updaterSV, viewDescriptorsSV);
177 }
178 mapperRegistry->startMapper(mapperPointer);
179 maybeRequestRender();
180 });
181
182 return jsi::Value(static_cast<double>(newMapperId));
183 }
184
stopMapper(jsi::Runtime & rt,const jsi::Value & mapperId)185 void NativeReanimatedModule::stopMapper(
186 jsi::Runtime &rt,
187 const jsi::Value &mapperId) {
188 unsigned long id = mapperId.asNumber();
189 scheduler->scheduleOnUI([=] {
190 mapperRegistry->stopMapper(id);
191 maybeRequestRender();
192 });
193 }
194
registerEventHandler(jsi::Runtime & rt,const jsi::Value & eventHash,const jsi::Value & worklet)195 jsi::Value NativeReanimatedModule::registerEventHandler(
196 jsi::Runtime &rt,
197 const jsi::Value &eventHash,
198 const jsi::Value &worklet) {
199 static unsigned long EVENT_HANDLER_ID = 1;
200
201 unsigned long newRegistrationId = EVENT_HANDLER_ID++;
202 auto eventName = eventHash.asString(rt).utf8(rt);
203 auto handlerShareable = ShareableValue::adapt(rt, worklet, this);
204
205 scheduler->scheduleOnUI([=] {
206 auto handlerFunction =
207 handlerShareable->getValue(*runtime).asObject(*runtime).asFunction(
208 *runtime);
209 auto handler = std::make_shared<WorkletEventHandler>(
210 newRegistrationId, eventName, std::move(handlerFunction));
211 eventHandlerRegistry->registerEventHandler(handler);
212 });
213
214 return jsi::Value(static_cast<double>(newRegistrationId));
215 }
216
unregisterEventHandler(jsi::Runtime & rt,const jsi::Value & registrationId)217 void NativeReanimatedModule::unregisterEventHandler(
218 jsi::Runtime &rt,
219 const jsi::Value ®istrationId) {
220 unsigned long id = registrationId.asNumber();
221 scheduler->scheduleOnUI(
222 [=] { eventHandlerRegistry->unregisterEventHandler(id); });
223 }
224
getViewProp(jsi::Runtime & rt,const jsi::Value & viewTag,const jsi::Value & propName,const jsi::Value & callback)225 jsi::Value NativeReanimatedModule::getViewProp(
226 jsi::Runtime &rt,
227 const jsi::Value &viewTag,
228 const jsi::Value &propName,
229 const jsi::Value &callback) {
230 const int viewTagInt = static_cast<int>(viewTag.asNumber());
231 std::string propNameStr = propName.asString(rt).utf8(rt);
232 jsi::Function fun = callback.getObject(rt).asFunction(rt);
233 std::shared_ptr<jsi::Function> funPtr =
234 std::make_shared<jsi::Function>(std::move(fun));
235
236 scheduler->scheduleOnUI([&rt, viewTagInt, funPtr, this, propNameStr]() {
237 const jsi::String propNameValue =
238 jsi::String::createFromUtf8(rt, propNameStr);
239 jsi::Value result = propObtainer(rt, viewTagInt, propNameValue);
240 std::string resultStr = result.asString(rt).utf8(rt);
241
242 scheduler->scheduleOnJS([&rt, resultStr, funPtr]() {
243 const jsi::String resultValue =
244 jsi::String::createFromUtf8(rt, resultStr);
245 funPtr->call(rt, resultValue);
246 });
247 });
248
249 return jsi::Value::undefined();
250 }
251
enableLayoutAnimations(jsi::Runtime & rt,const jsi::Value & config)252 jsi::Value NativeReanimatedModule::enableLayoutAnimations(
253 jsi::Runtime &rt,
254 const jsi::Value &config) {
255 FeaturesConfig::setLayoutAnimationEnabled(config.getBool());
256 return jsi::Value::undefined();
257 }
258
configureProps(jsi::Runtime & rt,const jsi::Value & uiProps,const jsi::Value & nativeProps)259 jsi::Value NativeReanimatedModule::configureProps(
260 jsi::Runtime &rt,
261 const jsi::Value &uiProps,
262 const jsi::Value &nativeProps) {
263 configurePropsPlatformFunction(rt, uiProps, nativeProps);
264 return jsi::Value::undefined();
265 }
266
onEvent(std::string eventName,std::string eventAsString)267 void NativeReanimatedModule::onEvent(
268 std::string eventName,
269 std::string eventAsString) {
270 try {
271 eventHandlerRegistry->processEvent(*runtime, eventName, eventAsString);
272 mapperRegistry->execute(*runtime);
273 if (mapperRegistry->needRunOnRender()) {
274 maybeRequestRender();
275 }
276 } catch (std::exception &e) {
277 std::string str = e.what();
278 this->errorHandler->setError(str);
279 this->errorHandler->raise();
280 } catch (...) {
281 std::string str = "OnEvent error";
282 this->errorHandler->setError(str);
283 this->errorHandler->raise();
284 }
285 }
286
isAnyHandlerWaitingForEvent(std::string eventName)287 bool NativeReanimatedModule::isAnyHandlerWaitingForEvent(
288 std::string eventName) {
289 return eventHandlerRegistry->isAnyHandlerWaitingForEvent(eventName);
290 }
291
maybeRequestRender()292 void NativeReanimatedModule::maybeRequestRender() {
293 if (!renderRequested) {
294 renderRequested = true;
295 requestRender(onRenderCallback, *this->runtime);
296 }
297 }
298
onRender(double timestampMs)299 void NativeReanimatedModule::onRender(double timestampMs) {
300 try {
301 std::vector<FrameCallback> callbacks = frameCallbacks;
302 frameCallbacks.clear();
303 for (auto &callback : callbacks) {
304 callback(timestampMs);
305 }
306 mapperRegistry->execute(*runtime);
307
308 if (mapperRegistry->needRunOnRender()) {
309 maybeRequestRender();
310 }
311 } catch (std::exception &e) {
312 std::string str = e.what();
313 this->errorHandler->setError(str);
314 this->errorHandler->raise();
315 } catch (...) {
316 std::string str = "OnRender error";
317 this->errorHandler->setError(str);
318 this->errorHandler->raise();
319 }
320 }
321
registerSensor(jsi::Runtime & rt,const jsi::Value & sensorType,const jsi::Value & interval,const jsi::Value & sensorDataContainer)322 jsi::Value NativeReanimatedModule::registerSensor(
323 jsi::Runtime &rt,
324 const jsi::Value &sensorType,
325 const jsi::Value &interval,
326 const jsi::Value &sensorDataContainer) {
327 return animatedSensorModule.registerSensor(
328 rt, sensorType, interval, sensorDataContainer);
329 }
330
unregisterSensor(jsi::Runtime & rt,const jsi::Value & sensorId)331 void NativeReanimatedModule::unregisterSensor(
332 jsi::Runtime &rt,
333 const jsi::Value &sensorId) {
334 animatedSensorModule.unregisterSensor(sensorId);
335 }
336
subscribeForKeyboardEvents(jsi::Runtime & rt,const jsi::Value & keyboardEventContainer)337 jsi::Value NativeReanimatedModule::subscribeForKeyboardEvents(
338 jsi::Runtime &rt,
339 const jsi::Value &keyboardEventContainer) {
340 jsi::Object keyboardEventObj = keyboardEventContainer.getObject(rt);
341 std::unordered_map<std::string, std::shared_ptr<ShareableValue>>
342 sharedProperties;
343 std::shared_ptr<ShareableValue> keyboardStateShared = ShareableValue::adapt(
344 rt, keyboardEventObj.getProperty(rt, "state"), this);
345 std::shared_ptr<ShareableValue> heightShared = ShareableValue::adapt(
346 rt, keyboardEventObj.getProperty(rt, "height"), this);
347
348 auto keyboardEventDataUpdater =
349 [this, &rt, keyboardStateShared, heightShared](
350 int keyboardState, int height) {
351 auto &keyboardStateValue =
352 ValueWrapper::asMutableValue(keyboardStateShared->valueContainer);
353 keyboardStateValue->setValue(rt, jsi::Value(keyboardState));
354
355 auto &heightMutableValue =
356 ValueWrapper::asMutableValue(heightShared->valueContainer);
357 heightMutableValue->setValue(rt, jsi::Value(height));
358
359 this->mapperRegistry->execute(*this->runtime);
360 };
361
362 return subscribeForKeyboardEventsFunction(keyboardEventDataUpdater);
363 }
364
unsubscribeFromKeyboardEvents(jsi::Runtime & rt,const jsi::Value & listenerId)365 void NativeReanimatedModule::unsubscribeFromKeyboardEvents(
366 jsi::Runtime &rt,
367 const jsi::Value &listenerId) {
368 unsubscribeFromKeyboardEventsFunction(listenerId.asNumber());
369 }
370
371 } // namespace reanimated
372