diff --git a/ReactCommon/react/renderer/uimanager/SurfaceRegistryBinding.cpp b/ReactCommon/react/renderer/uimanager/SurfaceRegistryBinding.cpp new file mode 100644 index 00000000000..129ee6597f6 --- /dev/null +++ b/ReactCommon/react/renderer/uimanager/SurfaceRegistryBinding.cpp @@ -0,0 +1,105 @@ +/* + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include "SurfaceRegistryBinding.h" +#include +#include +#include +#include "bindingUtils.h" + +namespace facebook::react { + +void SurfaceRegistryBinding::startSurface( + jsi::Runtime &runtime, + SurfaceId surfaceId, + std::string const &moduleName, + folly::dynamic const &initalProps, + DisplayMode displayMode) { + SystraceSection s("SurfaceRegistryBinding::startSurface"); + folly::dynamic parameters = folly::dynamic::object(); + parameters["rootTag"] = surfaceId; + parameters["initialProps"] = initalProps; + parameters["fabric"] = true; + + if (moduleName != "LogBox" && + runtime.global().hasProperty(runtime, "RN$SurfaceRegistry")) { + auto registry = + runtime.global().getPropertyAsObject(runtime, "RN$SurfaceRegistry"); + auto method = registry.getPropertyAsFunction(runtime, "renderSurface"); + + method.call( + runtime, + {jsi::String::createFromUtf8(runtime, moduleName), + jsi::valueFromDynamic(runtime, parameters), + jsi::Value(runtime, displayModeToInt(displayMode))}); + } else { + callMethodOfModule( + runtime, + "AppRegistry", + "runApplication", + {jsi::String::createFromUtf8(runtime, moduleName), + jsi::valueFromDynamic(runtime, parameters), + jsi::Value(runtime, displayModeToInt(displayMode))}); + } +} + +void SurfaceRegistryBinding::setSurfaceProps( + jsi::Runtime &runtime, + SurfaceId surfaceId, + std::string const &moduleName, + folly::dynamic const &initalProps, + DisplayMode displayMode) { + SystraceSection s("UIManagerBinding::setSurfaceProps"); + folly::dynamic parameters = folly::dynamic::object(); + parameters["rootTag"] = surfaceId; + parameters["initialProps"] = initalProps; + parameters["fabric"] = true; + + if (moduleName != "LogBox" && + runtime.global().hasProperty(runtime, "RN$SurfaceRegistry")) { + auto registry = + runtime.global().getPropertyAsObject(runtime, "RN$SurfaceRegistry"); + auto method = registry.getPropertyAsFunction(runtime, "setSurfaceProps"); + + method.call( + runtime, + {jsi::String::createFromUtf8(runtime, moduleName), + jsi::valueFromDynamic(runtime, parameters), + jsi::Value(runtime, displayModeToInt(displayMode))}); + } else { + callMethodOfModule( + runtime, + "AppRegistry", + "setSurfaceProps", + {jsi::String::createFromUtf8(runtime, moduleName), + jsi::valueFromDynamic(runtime, parameters), + jsi::Value(runtime, displayModeToInt(displayMode))}); + } +} + +void SurfaceRegistryBinding::stopSurface( + jsi::Runtime &runtime, + SurfaceId surfaceId) { + auto global = runtime.global(); + if (global.hasProperty(runtime, "RN$Bridgeless")) { + if (!global.hasProperty(runtime, "RN$stopSurface")) { + // ReactFabric module has not been loaded yet; there's no surface to stop. + return; + } + // Bridgeless mode uses a custom JSI binding instead of callable module. + global.getPropertyAsFunction(runtime, "RN$stopSurface") + .call(runtime, {jsi::Value{surfaceId}}); + } else { + callMethodOfModule( + runtime, + "ReactFabric", + "unmountComponentAtNode", + {jsi::Value{surfaceId}}); + } +} + +} // namespace facebook::react diff --git a/ReactCommon/react/renderer/uimanager/SurfaceRegistryBinding.h b/ReactCommon/react/renderer/uimanager/SurfaceRegistryBinding.h new file mode 100644 index 00000000000..9e71eb8f485 --- /dev/null +++ b/ReactCommon/react/renderer/uimanager/SurfaceRegistryBinding.h @@ -0,0 +1,49 @@ +/* + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#pragma once + +#include +#include + +namespace facebook::react { + +class SurfaceRegistryBinding final { + public: + SurfaceRegistryBinding() = delete; + + /* + * Starts React Native Surface with given id, moduleName, and props. + * Thread synchronization must be enforced externally. + */ + static void startSurface( + jsi::Runtime &runtime, + SurfaceId surfaceId, + std::string const &moduleName, + folly::dynamic const &initalProps, + DisplayMode displayMode); + + /* + * Updates the React Native Surface identified with surfaceId and moduleName + * with the given props. + * Thread synchronization must be enforced externally. + */ + static void setSurfaceProps( + jsi::Runtime &runtime, + SurfaceId surfaceId, + std::string const &moduleName, + folly::dynamic const &initalProps, + DisplayMode displayMode); + + /* + * Stops React Native Surface with given id. + * Thread synchronization must be enforced externally. + */ + static void stopSurface(jsi::Runtime &runtime, SurfaceId surfaceId); +}; + +} // namespace facebook::react diff --git a/ReactCommon/react/renderer/uimanager/UIManager.cpp b/ReactCommon/react/renderer/uimanager/UIManager.cpp index a91d73c610c..4a279b05936 100644 --- a/ReactCommon/react/renderer/uimanager/UIManager.cpp +++ b/ReactCommon/react/renderer/uimanager/UIManager.cpp @@ -12,6 +12,7 @@ #include #include #include +#include #include #include @@ -169,12 +170,7 @@ void UIManager::startSurface( runtimeExecutor_([=](jsi::Runtime &runtime) { SystraceSection s("UIManager::startSurface::onRuntime"); - auto uiManagerBinding = UIManagerBinding::getBinding(runtime); - if (!uiManagerBinding) { - return; - } - - uiManagerBinding->startSurface( + SurfaceRegistryBinding::startSurface( runtime, surfaceId, moduleName, props, displayMode); }); } @@ -187,12 +183,7 @@ void UIManager::setSurfaceProps( SystraceSection s("UIManager::setSurfaceProps"); runtimeExecutor_([=](jsi::Runtime &runtime) { - auto uiManagerBinding = UIManagerBinding::getBinding(runtime); - if (!uiManagerBinding) { - return; - } - - uiManagerBinding->setSurfaceProps( + SurfaceRegistryBinding::setSurfaceProps( runtime, surfaceId, moduleName, props, displayMode); }); } @@ -212,12 +203,7 @@ ShadowTree::Unique UIManager::stopSurface(SurfaceId surfaceId) const { // the JavaScript side will not be able to reference a `ShadowTree` and will // fail silently. runtimeExecutor_([=](jsi::Runtime &runtime) { - auto uiManagerBinding = UIManagerBinding::getBinding(runtime); - if (!uiManagerBinding) { - return; - } - - uiManagerBinding->stopSurface(runtime, surfaceId); + SurfaceRegistryBinding::stopSurface(runtime, surfaceId); }); if (leakChecker_) { diff --git a/ReactCommon/react/renderer/uimanager/UIManagerBinding.cpp b/ReactCommon/react/renderer/uimanager/UIManagerBinding.cpp index e9b675a8999..4b314adf37c 100644 --- a/ReactCommon/react/renderer/uimanager/UIManagerBinding.cpp +++ b/ReactCommon/react/renderer/uimanager/UIManagerBinding.cpp @@ -15,49 +15,10 @@ #include #include +#include "bindingUtils.h" + namespace facebook::react { -static jsi::Value getModule( - jsi::Runtime &runtime, - std::string const &moduleName) { - auto batchedBridge = - runtime.global().getPropertyAsObject(runtime, "__fbBatchedBridge"); - auto getCallableModule = - batchedBridge.getPropertyAsFunction(runtime, "getCallableModule"); - auto moduleAsValue = getCallableModule.callWithThis( - runtime, - batchedBridge, - {jsi::String::createFromUtf8(runtime, moduleName)}); - if (!moduleAsValue.isObject()) { - LOG(ERROR) << "getModule of " << moduleName << " is not an object"; - } - react_native_assert(moduleAsValue.isObject()); - return moduleAsValue; -} - -static bool checkBatchedBridgeIsActive(jsi::Runtime &runtime) { - if (!runtime.global().hasProperty(runtime, "__fbBatchedBridge")) { - LOG(ERROR) - << "getPropertyAsObject: property '__fbBatchedBridge' is undefined, expected an Object"; - return false; - } - return true; -} - -static bool checkGetCallableModuleIsActive(jsi::Runtime &runtime) { - if (!checkBatchedBridgeIsActive(runtime)) { - return false; - } - auto batchedBridge = - runtime.global().getPropertyAsObject(runtime, "__fbBatchedBridge"); - if (!batchedBridge.hasProperty(runtime, "getCallableModule")) { - LOG(ERROR) - << "getPropertyAsFunction: function 'getCallableModule' is undefined, expected a Function"; - return false; - } - return true; -} - void UIManagerBinding::createAndInstallIfNeeded( jsi::Runtime &runtime, RuntimeExecutor const &runtimeExecutor, @@ -101,29 +62,6 @@ UIManagerBinding::~UIManagerBinding() { << this << ")."; } -static jsi::Value callMethodOfModule( - jsi::Runtime &runtime, - std::string const &moduleName, - std::string const &methodName, - std::initializer_list args) { - if (checkGetCallableModuleIsActive(runtime)) { - auto module = getModule(runtime, moduleName); - if (module.isObject()) { - jsi::Object object = module.asObject(runtime); - react_native_assert(object.hasProperty(runtime, methodName.c_str())); - if (object.hasProperty(runtime, methodName.c_str())) { - auto method = object.getPropertyAsFunction(runtime, methodName.c_str()); - return method.callWithThis(runtime, object, args); - } else { - LOG(ERROR) << "getPropertyAsFunction: property '" << methodName - << "' is undefined, expected a Function"; - } - } - } - - return jsi::Value::undefined(); -} - jsi::Value UIManagerBinding::getInspectorDataForInstance( jsi::Runtime &runtime, EventEmitter const &eventEmitter) const { @@ -151,94 +89,6 @@ jsi::Value UIManagerBinding::getInspectorDataForInstance( {std::move(instanceHandle)}); } -void UIManagerBinding::startSurface( - jsi::Runtime &runtime, - SurfaceId surfaceId, - std::string const &moduleName, - folly::dynamic const &initalProps, - DisplayMode displayMode) const { - SystraceSection s("UIManagerBinding::startSurface"); - folly::dynamic parameters = folly::dynamic::object(); - parameters["rootTag"] = surfaceId; - parameters["initialProps"] = initalProps; - parameters["fabric"] = true; - - if (moduleName != "LogBox" && - runtime.global().hasProperty(runtime, "RN$SurfaceRegistry")) { - auto registry = - runtime.global().getPropertyAsObject(runtime, "RN$SurfaceRegistry"); - auto method = registry.getPropertyAsFunction(runtime, "renderSurface"); - - method.call( - runtime, - {jsi::String::createFromUtf8(runtime, moduleName), - jsi::valueFromDynamic(runtime, parameters), - jsi::Value(runtime, displayModeToInt(displayMode))}); - } else { - callMethodOfModule( - runtime, - "AppRegistry", - "runApplication", - {jsi::String::createFromUtf8(runtime, moduleName), - jsi::valueFromDynamic(runtime, parameters), - jsi::Value(runtime, displayModeToInt(displayMode))}); - } -} - -void UIManagerBinding::setSurfaceProps( - jsi::Runtime &runtime, - SurfaceId surfaceId, - std::string const &moduleName, - folly::dynamic const &initalProps, - DisplayMode displayMode) const { - SystraceSection s("UIManagerBinding::setSurfaceProps"); - folly::dynamic parameters = folly::dynamic::object(); - parameters["rootTag"] = surfaceId; - parameters["initialProps"] = initalProps; - parameters["fabric"] = true; - - if (moduleName != "LogBox" && - runtime.global().hasProperty(runtime, "RN$SurfaceRegistry")) { - auto registry = - runtime.global().getPropertyAsObject(runtime, "RN$SurfaceRegistry"); - auto method = registry.getPropertyAsFunction(runtime, "setSurfaceProps"); - - method.call( - runtime, - {jsi::String::createFromUtf8(runtime, moduleName), - jsi::valueFromDynamic(runtime, parameters), - jsi::Value(runtime, displayModeToInt(displayMode))}); - } else { - callMethodOfModule( - runtime, - "AppRegistry", - "setSurfaceProps", - {jsi::String::createFromUtf8(runtime, moduleName), - jsi::valueFromDynamic(runtime, parameters), - jsi::Value(runtime, displayModeToInt(displayMode))}); - } -} - -void UIManagerBinding::stopSurface(jsi::Runtime &runtime, SurfaceId surfaceId) - const { - auto global = runtime.global(); - if (global.hasProperty(runtime, "RN$Bridgeless")) { - if (!global.hasProperty(runtime, "RN$stopSurface")) { - // ReactFabric module has not been loaded yet; there's no surface to stop. - return; - } - // Bridgeless mode uses a custom JSI binding instead of callable module. - global.getPropertyAsFunction(runtime, "RN$stopSurface") - .call(runtime, {jsi::Value{surfaceId}}); - } else { - callMethodOfModule( - runtime, - "ReactFabric", - "unmountComponentAtNode", - {jsi::Value{surfaceId}}); - } -} - void UIManagerBinding::dispatchEvent( jsi::Runtime &runtime, EventTarget const *eventTarget, diff --git a/ReactCommon/react/renderer/uimanager/UIManagerBinding.h b/ReactCommon/react/renderer/uimanager/UIManagerBinding.h index e14b7e24cf3..d93808ba1ac 100644 --- a/ReactCommon/react/renderer/uimanager/UIManagerBinding.h +++ b/ReactCommon/react/renderer/uimanager/UIManagerBinding.h @@ -43,39 +43,10 @@ class UIManagerBinding : public jsi::HostObject { ~UIManagerBinding(); - /* - * Starts React Native Surface with given id, moduleName, and props. - * Thread synchronization must be enforced externally. - */ - void startSurface( - jsi::Runtime &runtime, - SurfaceId surfaceId, - std::string const &moduleName, - folly::dynamic const &initalProps, - DisplayMode displayMode) const; - - /* - * Updates the React Native Surface identified with surfaceId and moduleName - * with the given props. - * Thread synchronization must be enforced externally. - */ - void setSurfaceProps( - jsi::Runtime &runtime, - SurfaceId surfaceId, - std::string const &moduleName, - folly::dynamic const &props, - DisplayMode displayMode) const; - jsi::Value getInspectorDataForInstance( jsi::Runtime &runtime, EventEmitter const &eventEmitter) const; - /* - * Stops React Native Surface with given id. - * Thread synchronization must be enforced externally. - */ - void stopSurface(jsi::Runtime &runtime, SurfaceId surfaceId) const; - /* * Delivers raw event data to JavaScript. * Thread synchronization must be enforced externally. diff --git a/ReactCommon/react/renderer/uimanager/bindingUtils.cpp b/ReactCommon/react/renderer/uimanager/bindingUtils.cpp new file mode 100644 index 00000000000..d98fab50c4c --- /dev/null +++ b/ReactCommon/react/renderer/uimanager/bindingUtils.cpp @@ -0,0 +1,79 @@ +/* + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include "bindingUtils.h" + +#include +#include + +namespace facebook::react { + +static jsi::Value getModule( + jsi::Runtime &runtime, + std::string const &moduleName) { + auto batchedBridge = + runtime.global().getPropertyAsObject(runtime, "__fbBatchedBridge"); + auto getCallableModule = + batchedBridge.getPropertyAsFunction(runtime, "getCallableModule"); + auto moduleAsValue = getCallableModule.callWithThis( + runtime, + batchedBridge, + {jsi::String::createFromUtf8(runtime, moduleName)}); + if (!moduleAsValue.isObject()) { + LOG(ERROR) << "getModule of " << moduleName << " is not an object"; + } + react_native_assert(moduleAsValue.isObject()); + return moduleAsValue; +} + +static bool checkBatchedBridgeIsActive(jsi::Runtime &runtime) { + if (!runtime.global().hasProperty(runtime, "__fbBatchedBridge")) { + LOG(ERROR) + << "getPropertyAsObject: property '__fbBatchedBridge' is undefined, expected an Object"; + return false; + } + return true; +} + +static bool checkGetCallableModuleIsActive(jsi::Runtime &runtime) { + if (!checkBatchedBridgeIsActive(runtime)) { + return false; + } + auto batchedBridge = + runtime.global().getPropertyAsObject(runtime, "__fbBatchedBridge"); + if (!batchedBridge.hasProperty(runtime, "getCallableModule")) { + LOG(ERROR) + << "getPropertyAsFunction: function 'getCallableModule' is undefined, expected a Function"; + return false; + } + return true; +} + +jsi::Value callMethodOfModule( + jsi::Runtime &runtime, + std::string const &moduleName, + std::string const &methodName, + std::initializer_list args) { + if (checkGetCallableModuleIsActive(runtime)) { + auto module = getModule(runtime, moduleName); + if (module.isObject()) { + jsi::Object object = module.asObject(runtime); + react_native_assert(object.hasProperty(runtime, methodName.c_str())); + if (object.hasProperty(runtime, methodName.c_str())) { + auto method = object.getPropertyAsFunction(runtime, methodName.c_str()); + return method.callWithThis(runtime, object, args); + } else { + LOG(ERROR) << "getPropertyAsFunction: property '" << methodName + << "' is undefined, expected a Function"; + } + } + } + + return jsi::Value::undefined(); +} + +} // namespace facebook::react diff --git a/ReactCommon/react/renderer/uimanager/bindingUtils.h b/ReactCommon/react/renderer/uimanager/bindingUtils.h new file mode 100644 index 00000000000..e32854924bd --- /dev/null +++ b/ReactCommon/react/renderer/uimanager/bindingUtils.h @@ -0,0 +1,20 @@ +/* + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#pragma once + +#include + +namespace facebook::react { + +jsi::Value callMethodOfModule( + jsi::Runtime &runtime, + std::string const &moduleName, + std::string const &methodName, + std::initializer_list args); + +} // namespace facebook::react diff --git a/packages/rn-tester/Podfile.lock b/packages/rn-tester/Podfile.lock index 898d8d5b859..5bc0b30a0a4 100644 --- a/packages/rn-tester/Podfile.lock +++ b/packages/rn-tester/Podfile.lock @@ -881,7 +881,7 @@ SPEC CHECKSUMS: CocoaAsyncSocket: 065fd1e645c7abab64f7a6a2007a48038fdc6a99 DoubleConversion: 831926d9b8bf8166fd87886c4abab286c2422662 FBLazyVector: b81a2b70c72d8b0aefb652cea22c11e9ffd02949 - FBReactNativeSpec: 02b0c2bc3cf30c9ab1d5af08c22b5573bc6af06c + FBReactNativeSpec: 140e95aa3cc1f6084938f6b8123bb0c4398325d1 Flipper: 30e8eeeed6abdc98edaf32af0cda2f198be4b733 Flipper-Boost-iOSX: fd1e2b8cbef7e662a122412d7ac5f5bea715403c Flipper-DoubleConversion: 57ffbe81ef95306cc9e69c4aa3aeeeeb58a6a28c @@ -901,7 +901,7 @@ SPEC CHECKSUMS: React: f64c9f6db5428717922a3292ba6a448615a2e143 React-callinvoker: c5d61e29df57793f0dc10ec2bc01c846f863e51f React-Codegen: 2256e335ccce7326eeca6d7a668e05c4de259289 - React-Core: 22bc86b79dd931dbfb7fd2af91a35a98d41ceb64 + React-Core: 50d95abfb3c60d95e33a4b74e05e2a414bea4b73 React-CoreModules: a8e2bdc1ebbf8d440478456197abd58d1691f61a React-cxxreact: cfc1663dae1ea52b465bbf021ef7b1527c5dc80c React-Fabric: 002345cff43721617e0a3c0866f6f76bae8c50ff @@ -923,10 +923,10 @@ SPEC CHECKSUMS: React-RCTTest: 12bbd7fc2e72bd9920dc7286c5b8ef96639582b6 React-RCTText: e9146b2c0550a83d1335bfe2553760070a2d75c7 React-RCTVibration: 50be9c390f2da76045ef0dfdefa18b9cf9f35cfa - React-rncore: 5293698ae0222ddbaf47ce6193591b5fe3cb826c + React-rncore: 90798d1c013f1c62d0066c5618ddf8681c7a7c22 React-runtimeexecutor: 4b0c6eb341c7d3ceb5e2385cb0fdb9bf701024f3 ReactCommon: 7a2714d1128f965392b6f99a8b390e3aa38c9569 - ScreenshotManager: 99830e1bd3d2b595ef092bb20fe9bb644deb9082 + ScreenshotManager: ccf2b410b3c59385b26b8460a58cca8a8aca5e85 Yoga: c0d06f5380d34e939f55420669a60fe08b79bd75 YogaKit: f782866e155069a2cca2517aafea43200b01fd5a