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 ®istrationId) 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