1 #include "NativeReanimatedModule.h"
2 #include "ShareableValue.h"
3 #include "MapperRegistry.h"
4 #include "Mapper.h"
5 #include "RuntimeDecorator.h"
6 #include "EventHandlerRegistry.h"
7 #include "WorkletEventHandler.h"
8 #include "FrozenObject.h"
9 #include <functional>
10 #include <thread>
11 #include <memory>
12 #include "JSIStoreValueUser.h"
13 
14 using namespace facebook;
15 
16 namespace reanimated
17 {
18 
19 void extractMutables(jsi::Runtime &rt,
20                      std::shared_ptr<ShareableValue> sv,
21                      std::vector<std::shared_ptr<MutableValue>> &res)
22 {
23   switch (sv->type)
24   {
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     {
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     {
40       extractMutables(rt, it.second, res);
41     }
42     break;
43   default:
44     break;
45   }
46 }
47 
48 std::vector<std::shared_ptr<MutableValue>> extractMutablesFromArray(jsi::Runtime &rt, const jsi::Array &array, NativeReanimatedModule *module)
49 {
50   std::vector<std::shared_ptr<MutableValue>> res;
51   for (size_t i = 0, size = array.size(rt); i < size; i++)
52   {
53     auto shareable = ShareableValue::adapt(rt, array.getValueAtIndex(rt, i), module);
54     extractMutables(rt, shareable, res);
55   }
56   return res;
57 }
58 
59 NativeReanimatedModule::NativeReanimatedModule(std::shared_ptr<CallInvoker> jsInvoker,
60                                                std::shared_ptr<Scheduler> scheduler,
61                                                std::unique_ptr<jsi::Runtime> rt,
62                                                std::shared_ptr<ErrorHandler> errorHandler,
63                                                std::function<jsi::Value(jsi::Runtime &, const int, const jsi::String &)> propObtainer,
64                                                PlatformDepMethodsHolder platformDepMethodsHolder) : NativeReanimatedModuleSpec(jsInvoker),
65                                                   runtime(std::move(rt)),
66                                                   mapperRegistry(new MapperRegistry()),
67                                                   eventHandlerRegistry(new EventHandlerRegistry()),
68                                                   requestRender(platformDepMethodsHolder.requestRender),
69                                                   propObtainer(propObtainer),
70                                                   errorHandler(errorHandler),
71                                                   workletsCache(new WorkletsCache()),
72                                                   scheduler(scheduler)
73 {
74   auto requestAnimationFrame = [=](FrameCallback callback) {
75     frameCallbacks.push_back(callback);
76     maybeRequestRender();
77   };
78 
79   RuntimeDecorator::addNativeObjects(*runtime,
80                                      platformDepMethodsHolder.updaterFunction,
81                                      requestAnimationFrame,
82                                      platformDepMethodsHolder.scrollToFunction,
83                                      platformDepMethodsHolder.measuringFunction,
84                                      platformDepMethodsHolder.getCurrentTime);
85 }
86 
87 bool NativeReanimatedModule::isUIRuntime(jsi::Runtime &rt)
88 {
89   return runtime.get() == &rt;
90 }
91 
92 bool NativeReanimatedModule::isHostRuntime(jsi::Runtime &rt)
93 {
94   return !isUIRuntime(rt);
95 }
96 
97 void NativeReanimatedModule::installCoreFunctions(jsi::Runtime &rt, const jsi::Value &valueSetter)
98 {
99   this->valueSetter = ShareableValue::adapt(rt, valueSetter, this);
100 }
101 
102 jsi::Value NativeReanimatedModule::makeShareable(jsi::Runtime &rt, const jsi::Value &value)
103 {
104   return ShareableValue::adapt(rt, value, this)->getValue(rt);
105 }
106 
107 jsi::Value NativeReanimatedModule::makeMutable(jsi::Runtime &rt, const jsi::Value &value)
108 {
109   return ShareableValue::adapt(rt, value, this, ValueType::MutableValueType)->getValue(rt);
110 }
111 
112 jsi::Value NativeReanimatedModule::makeRemote(jsi::Runtime &rt, const jsi::Value &value)
113 {
114   return ShareableValue::adapt(rt, value, this, ValueType::RemoteObjectType)->getValue(rt);
115 }
116 
117 jsi::Value NativeReanimatedModule::startMapper(jsi::Runtime &rt, const jsi::Value &worklet, const jsi::Value &inputs, const jsi::Value &outputs)
118 {
119   static unsigned long MAPPER_ID = 1;
120 
121   unsigned long newMapperId = MAPPER_ID++;
122   auto mapperShareable = ShareableValue::adapt(rt, worklet, this);
123   auto inputMutables = extractMutablesFromArray(rt, inputs.asObject(rt).asArray(rt), this);
124   auto outputMutables = extractMutablesFromArray(rt, outputs.asObject(rt).asArray(rt), this);
125 
126   scheduler->scheduleOnUI([=] {
127     auto mapperFunction = mapperShareable->getValue(*runtime).asObject(*runtime).asFunction(*runtime);
128     std::shared_ptr<jsi::Function> mapperFunctionPointer = std::make_shared<jsi::Function>(std::move(mapperFunction));
129     std::shared_ptr<Mapper> mapperPointer = std::make_shared<Mapper>(this, newMapperId, mapperFunctionPointer, inputMutables, outputMutables);
130     mapperRegistry->startMapper(mapperPointer);
131     maybeRequestRender();
132   });
133 
134   return jsi::Value((double)newMapperId);
135 }
136 
137 void NativeReanimatedModule::stopMapper(jsi::Runtime &rt, const jsi::Value &mapperId)
138 {
139   unsigned long id = mapperId.asNumber();
140   scheduler->scheduleOnUI([=] {
141     mapperRegistry->stopMapper(id);
142     maybeRequestRender();
143   });
144 }
145 
146 jsi::Value NativeReanimatedModule::registerEventHandler(jsi::Runtime &rt, const jsi::Value &eventHash, const jsi::Value &worklet)
147 {
148   static unsigned long EVENT_HANDLER_ID = 1;
149 
150   unsigned long newRegistrationId = EVENT_HANDLER_ID++;
151   auto eventName = eventHash.asString(rt).utf8(rt);
152   auto handlerShareable = ShareableValue::adapt(rt, worklet, this);
153 
154   scheduler->scheduleOnUI([=] {
155     auto handlerFunction = handlerShareable->getValue(*runtime).asObject(*runtime).asFunction(*runtime);
156     auto handler = std::make_shared<WorkletEventHandler>(newRegistrationId, eventName, std::move(handlerFunction));
157     eventHandlerRegistry->registerEventHandler(handler);
158   });
159 
160   return jsi::Value((double)newRegistrationId);
161 }
162 
163 void NativeReanimatedModule::unregisterEventHandler(jsi::Runtime &rt, const jsi::Value &registrationId)
164 {
165   unsigned long id = registrationId.asNumber();
166   scheduler->scheduleOnUI([=] {
167     eventHandlerRegistry->unregisterEventHandler(id);
168   });
169 }
170 
171 jsi::Value NativeReanimatedModule::getViewProp(jsi::Runtime &rt, const jsi::Value &viewTag, const jsi::Value &propName, const jsi::Value &callback)
172 {
173 
174   const int viewTagInt = (int)viewTag.asNumber();
175   std::string propNameStr = propName.asString(rt).utf8(rt);
176   jsi::Function fun = callback.getObject(rt).asFunction(rt);
177   std::shared_ptr<jsi::Function> funPtr(new jsi::Function(std::move(fun)));
178 
179   scheduler->scheduleOnUI([&rt, viewTagInt, funPtr, this, propNameStr]() {
180     const jsi::String propNameValue = jsi::String::createFromUtf8(rt, propNameStr);
181     jsi::Value result = propObtainer(rt, viewTagInt, propNameValue);
182     std::string resultStr = result.asString(rt).utf8(rt);
183 
184     scheduler->scheduleOnJS([&rt, resultStr, funPtr]() {
185       const jsi::String resultValue = jsi::String::createFromUtf8(rt, resultStr);
186       funPtr->call(rt, resultValue);
187     });
188   });
189 
190   return jsi::Value::undefined();
191 }
192 
193 void NativeReanimatedModule::onEvent(std::string eventName, std::string eventAsString)
194 {
195    try
196     {
197       eventHandlerRegistry->processEvent(*runtime, eventName, eventAsString);
198       mapperRegistry->execute(*runtime);
199       if (mapperRegistry->needRunOnRender())
200       {
201         maybeRequestRender();
202       }
203     }
204     catch(std::exception &e) {
205      std::string str = e.what();
206      this->errorHandler->setError(str);
207      this->errorHandler->raise();
208    } catch(...) {
209      std::string str = "OnEvent error";
210      this->errorHandler->setError(str);
211      this->errorHandler->raise();
212   }
213 }
214 
215 bool NativeReanimatedModule::isAnyHandlerWaitingForEvent(std::string eventName) {
216   return eventHandlerRegistry->isAnyHandlerWaitingForEvent(eventName);
217 }
218 
219 
220 void NativeReanimatedModule::maybeRequestRender()
221 {
222   if (!renderRequested)
223   {
224     renderRequested = true;
225     requestRender([this](double timestampMs) {
226       this->renderRequested = false;
227       this->onRender(timestampMs);
228     }, *this->runtime);
229   }
230 }
231 
232 void NativeReanimatedModule::onRender(double timestampMs)
233 {
234   try
235   {
236     std::vector<FrameCallback> callbacks = frameCallbacks;
237     frameCallbacks.clear();
238     for (auto callback : callbacks)
239     {
240       callback(timestampMs);
241     }
242     mapperRegistry->execute(*runtime);
243 
244     if (mapperRegistry->needRunOnRender())
245     {
246       maybeRequestRender();
247     }
248   } catch(std::exception &e) {
249     std::string str = e.what();
250     this->errorHandler->setError(str);
251     this->errorHandler->raise();
252   } catch(...) {
253     std::string str = "OnRender error";
254     this->errorHandler->setError(str);
255     this->errorHandler->raise();
256   }
257 }
258 
259 NativeReanimatedModule::~NativeReanimatedModule()
260 {
261   StoreUser::clearStore();
262 }
263 
264 } // namespace reanimated
265