#include "GPUIWorkletsModule.h" #include "GpuiHost.h" #include #include #include #include #include #include #include #include #include #include #include #include namespace { bool animationTracingEnabled() { static const bool enabled = std::getenv("RN_GPUI_DEBUG_ANIMATION") != nullptr; return enabled; } using facebook::jsi::Runtime; using reanimated::PlatformDepMethodsHolder; using reanimated::ReanimatedModuleProxy; PlatformDepMethodsHolder platformMethods( const std::shared_ptr>& proxyHolder) { PlatformDepMethodsHolder methods; methods.requestRender = [](std::function callback) { static std::atomic requests{0}; const auto count = ++requests; if (animationTracingEnabled() && (count <= 5 || count % 60 == 0)) { LOG(INFO) << "[gpui-reanimated] requestRender count=" << count; } auto module = gpui_worklets::currentModule(); if (module) module->requestAnimationFrame(std::move(callback)); }; methods.synchronouslyUpdateUIPropsFunction = [](const int tag, const folly::dynamic& props) { rngpui::gpui_synchronously_update_props(tag, props); }; methods.getAnimationTimestamp = [] { return std::chrono::duration( std::chrono::steady_clock::now().time_since_epoch()) .count(); }; methods.registerSensor = [](int, int, int, std::function) { return 0; }; methods.unregisterSensor = [](int) {}; methods.setGestureStateFunction = [](int, int) {}; methods.maybeFlushUIUpdatesQueueFunction = [proxyHolder] { if (auto proxy = proxyHolder->lock()) { proxy->performOperations(); } }; methods.attachPseudoSelector = [](facebook::react::Tag, reanimated::PseudoSelector, std::function callback) { if (callback) callback(false); }; methods.detachPseudoSelector = [](facebook::react::Tag, reanimated::PseudoSelector) {}; #if defined(__APPLE__) methods.forceScreenSnapshotFunction = [](facebook::react::Tag) { return false; }; methods.readMountedViewPropsFunction = [](facebook::react::Tag) -> facebook::react::Props::Shared { return nullptr; }; #endif return methods; } class Module final : public facebook::react::NativeReanimatedModuleSpec { public: explicit Module(std::shared_ptr jsInvoker) : NativeReanimatedModuleSpec(std::move(jsInvoker)) {} bool installTurboModule(Runtime& runtime) { if (proxy_) return true; auto worklets = gpui_worklets::currentModule(); auto uiManager = rngpui::get_gpui_ui_manager(); if (!worklets || !worklets->uiRuntime() || !worklets->uiScheduler() || !uiManager) { throw facebook::jsi::JSError( runtime, "GPUI Reanimated requires initialized Worklets and Fabric"); } // The platform flush callback is constructed before the proxy exists. // Retain only a weak reference so the decorated UI runtime cannot keep // the module alive after React Native tears it down. auto proxyHolder = std::make_shared>(); auto methods = platformMethods(proxyHolder); proxy_ = std::make_shared( worklets->uiRuntime(), worklets->uiScheduler(), runtime, jsInvoker_, methods, false); *proxyHolder = proxy_; proxy_->init(methods); proxy_->initializeFabric(uiManager); LOG(INFO) << "[gpui-reanimated] module proxy initialized"; auto& uiRuntime = worklets::getJSIRuntimeFromWorkletRuntime(worklets->uiRuntime()); reanimated::RNRuntimeDecorator::decorate(runtime, uiRuntime, proxy_); std::weak_ptr weakProxy = proxy_; eventListener_ = std::make_shared( [weakProxy](const facebook::react::RawEvent& event) { auto proxy = weakProxy.lock(); if (!proxy) return false; const auto timestamp = std::chrono::duration( std::chrono::steady_clock::now().time_since_epoch()) .count(); static std::atomic events{0}; const auto count = ++events; if (animationTracingEnabled() && event.type.find("GestureHandler") != std::string::npos) { const auto* target = event.eventTarget.get(); const auto tag = target ? target->getTag() : -1; auto eventName = event.type; if (eventName.rfind("top", 0) == 0) { eventName = "on" + eventName.substr(3); } LOG(INFO) << "[gpui-reanimated] gesture lookup type=" << eventName << " tag=" << tag << " waiting=" << proxy->isAnyHandlerWaitingForEvent(eventName, tag); } if (animationTracingEnabled() && (count <= 10 || event.type.find("GestureHandler") != std::string::npos)) { LOG(INFO) << "[gpui-reanimated] raw event count=" << count << " type=" << event.type; } return proxy->handleRawEvent(event, timestamp); }); rngpui::register_gpui_event_listener(eventListener_); return true; } std::shared_ptr proxy_; std::shared_ptr eventListener_; }; } // namespace std::shared_ptr create_gpui_reanimated_module( const std::string& name, std::shared_ptr jsInvoker) { return rngpui::provideTurboModule(name, std::move(jsInvoker)); }