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