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