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