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