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 ABI47_0_0facebook; 20 21 namespace ABI47_0_0reanimated { 22 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 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 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 109 void NativeReanimatedModule::installCoreFunctions( 110 jsi::Runtime &rt, 111 const jsi::Value &valueSetter) { 112 this->valueSetter = ShareableValue::adapt(rt, valueSetter, this); 113 } 114 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 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 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 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 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 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 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 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 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 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 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 286 bool NativeReanimatedModule::isAnyHandlerWaitingForEvent( 287 std::string eventName) { 288 return eventHandlerRegistry->isAnyHandlerWaitingForEvent(eventName); 289 } 290 291 void NativeReanimatedModule::maybeRequestRender() { 292 if (!renderRequested) { 293 renderRequested = true; 294 requestRender(onRenderCallback, *this->runtime); 295 } 296 } 297 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 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 330 void NativeReanimatedModule::unregisterSensor( 331 jsi::Runtime &rt, 332 const jsi::Value &sensorId) { 333 animatedSensorModule.unregisterSensor(sensorId); 334 } 335 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 364 void NativeReanimatedModule::unsubscribeFromKeyboardEvents( 365 jsi::Runtime &rt, 366 const jsi::Value &listenerId) { 367 unsubscribeFromKeyboardEventsFunction(listenerId.asNumber()); 368 } 369 370 } // namespace reanimated 371