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