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 facebook;
20
21 namespace reanimated {
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 ®istrationId) {
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