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 &registrationId) {
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