Do not store .cpp/.h files inside src/main/java - fabricjni (#34435)

Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/34435

Currently we expose native code (.h, .cpp) inside the src/main/java folder.
This is making impossible for users on New Architecture to open the project
inside Android Studio.

The problem is that the src/main/java is reserved to Java/Kotlin sources only.
AGP 7.2 also removed support for mixed source roots:
https://developer.android.com/studio/releases/gradle-plugin#duplicate-content-roots

This is essentially forcing users to write Java code without any autocompletion
as all the React Native Java classes are considered C++ files.

I'm addressing this issue folder by folder by moving them
from ReactAndroid/src/main/java/com/facebook/... to ReactAndroid/src/main/jni/react/...

This is the diff for fabricjni

Changelog:
[Internal] [Changed] - Do not store .cpp/.h files inside src/main/java - fabricjni

Reviewed By: cipolleschi

Differential Revision: D38741130

fbshipit-source-id: f9e3e4514d3ae0ddeac65256928d71d5134d08f8
This commit is contained in:
Nicola Corti
2022-08-17 04:58:24 -07:00
committed by Facebook GitHub Bot
parent 1bd27609b3
commit 4706d13ec8
34 changed files with 4 additions and 4 deletions
@@ -42,7 +42,6 @@ rn_android_library(
react_native_target("java/com/facebook/debug/holder:holder"),
react_native_target("java/com/facebook/react/bridge:bridge"),
react_native_target("java/com/facebook/react/config:config"),
react_native_target("java/com/facebook/react/fabric/jni:jni"),
react_native_target("java/com/facebook/react/module/annotations:annotations"),
react_native_target("java/com/facebook/react/modules/core:core"),
react_native_target("java/com/facebook/react/modules/i18nmanager:i18nmanager"),
@@ -52,5 +51,6 @@ rn_android_library(
react_native_target("java/com/facebook/react/views/view:view"),
react_native_target("java/com/facebook/react/views/text:text"),
react_native_target("java/com/facebook/react/touch:touch"),
react_native_target("jni/react/fabric:jni"),
] + KOTLIN_STDLIB_DEPS,
)
@@ -294,7 +294,7 @@ public class FabricUIManager implements UIManager, LifecycleEventListener {
* @return a {@link ReadableMap} that contains metadata associated to the React Component that
* rendered the Android View received as a parameter. For more details about the keys stored
* in the {@link ReadableMap} refer to the "getInspectorDataForInstance" method from
* com/facebook/react/fabric/jni/Binding.cpp file.
* jni/react/fabric/Binding.cpp file.
*/
@UiThread
@ThreadConfined(UI)
@@ -1,69 +0,0 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#include <jsi/jsi.h>
#include <react/renderer/core/EventBeat.h>
#include <react/renderer/uimanager/primitives.h>
#include "AsyncEventBeat.h"
namespace facebook::react {
AsyncEventBeat::AsyncEventBeat(
EventBeat::SharedOwnerBox const &ownerBox,
EventBeatManager *eventBeatManager,
RuntimeExecutor runtimeExecutor,
jni::global_ref<jobject> javaUIManager)
: EventBeat(ownerBox),
eventBeatManager_(eventBeatManager),
runtimeExecutor_(std::move(runtimeExecutor)),
javaUIManager_(std::move(javaUIManager)) {
eventBeatManager->addObserver(*this);
}
AsyncEventBeat::~AsyncEventBeat() {
eventBeatManager_->removeObserver(*this);
}
void AsyncEventBeat::tick() const {
if (!isRequested_ || isBeatCallbackScheduled_) {
return;
}
isRequested_ = false;
isBeatCallbackScheduled_ = true;
runtimeExecutor_([this, ownerBox = ownerBox_](jsi::Runtime &runtime) {
isBeatCallbackScheduled_ = false;
auto owner = ownerBox->owner.lock();
if (!owner) {
return;
}
if (beatCallback_) {
beatCallback_(runtime);
}
});
}
void AsyncEventBeat::induce() const {
tick();
}
void AsyncEventBeat::request() const {
bool alreadyRequested = isRequested_;
EventBeat::request();
if (!alreadyRequested) {
// Notifies java side that an event will be dispatched (e.g. LayoutEvent)
static auto onRequestEventBeat =
jni::findClassStatic("com/facebook/react/fabric/FabricUIManager")
->getMethod<void()>("onRequestEventBeat");
onRequestEventBeat(javaUIManager_);
}
}
} // namespace facebook::react
@@ -1,39 +0,0 @@
/*
* Copyright (c) Meta Platforms, Inc. and 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 <react/renderer/core/EventBeat.h>
#include "EventBeatManager.h"
namespace facebook::react {
class AsyncEventBeat final : public EventBeat, public EventBeatManagerObserver {
public:
AsyncEventBeat(
EventBeat::SharedOwnerBox const &ownerBox,
EventBeatManager *eventBeatManager,
RuntimeExecutor runtimeExecutor,
jni::global_ref<jobject> javaUIManager);
~AsyncEventBeat() override;
void tick() const override;
void induce() const override;
void request() const override;
private:
EventBeatManager *eventBeatManager_;
RuntimeExecutor runtimeExecutor_;
jni::global_ref<jobject> javaUIManager_;
mutable std::atomic<bool> isBeatCallbackScheduled_{false};
};
} // namespace facebook::react
@@ -1,55 +0,0 @@
load("//tools/build_defs/oss:rn_defs.bzl", "ANDROID", "FBJNI_TARGET", "react_native_target", "react_native_xplat_target", "rn_xplat_cxx_library", "subdir_glob")
rn_xplat_cxx_library(
name = "jni",
srcs = glob(["*.cpp"]),
headers = glob(["*.h"]),
header_namespace = "",
exported_headers = subdir_glob(
[
("", "**/*.h"),
],
prefix = "react/fabric",
),
fbandroid_allow_jni_merging = True,
labels = [
"pfh:ReactNative_CommonInfrastructurePlaceholder",
"supermodule:xplat/default/public.react_native.infra",
],
platforms = ANDROID,
preprocessor_flags = [
"-DLOG_TAG=\"ReactNative\"",
"-DWITH_FBSYSTRACE=1",
],
soname = "libfabricjni.$(ext)",
visibility = ["PUBLIC"],
deps = [
react_native_xplat_target("react/renderer/mapbuffer:mapbuffer"),
react_native_xplat_target("react/config:config"),
react_native_xplat_target("react/renderer/animations:animations"),
react_native_xplat_target("react/renderer/graphics:graphics"),
react_native_xplat_target("react/renderer/uimanager:uimanager"),
react_native_xplat_target("react/renderer/scheduler:scheduler"),
react_native_xplat_target("react/renderer/mounting:mounting"),
react_native_xplat_target("react/renderer/componentregistry:componentregistry"),
react_native_xplat_target("react/renderer/components/scrollview:scrollview"),
react_native_xplat_target("runtimeexecutor:runtimeexecutor"),
react_native_target("jni/react/jni:jni"),
"//xplat/fbsystrace:fbsystrace",
"//xplat/jsi:JSIDynamic",
"//xplat/jsi:jsi",
"//xplat/third-party/linker_lib:atomic",
FBJNI_TARGET,
# TODO T71316899: Extract CoreComponentsRegistry out of this module
# The following dependencies are required by CoreComponentsRegistry
"//xplat/js/react-native-github:generated_components-rncore",
react_native_xplat_target("react/renderer/components/image:image"),
react_native_xplat_target("react/renderer/components/modal:modal"),
react_native_xplat_target("react/renderer/components/slider:slider"),
react_native_xplat_target("react/renderer/components/switch:androidswitch"),
react_native_xplat_target("react/renderer/components/progressbar:androidprogressbar"),
react_native_xplat_target("react/renderer/components/text:text"),
react_native_xplat_target("react/renderer/components/view:view"),
react_native_xplat_target("react/renderer/components/textinput:androidtextinput"),
],
)
@@ -1,659 +0,0 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#include "Binding.h"
#include "AsyncEventBeat.h"
#include "EventEmitterWrapper.h"
#include "JBackgroundExecutor.h"
#include "ReactNativeConfigHolder.h"
#include "StateWrapperImpl.h"
#include <cfenv>
#include <cmath>
#include <fbjni/fbjni.h>
#include <jsi/JSIDynamic.h>
#include <jsi/jsi.h>
#include <react/renderer/animations/LayoutAnimationDriver.h>
#include <react/renderer/componentregistry/ComponentDescriptorFactory.h>
#include <react/renderer/components/scrollview/ScrollViewProps.h>
#include <react/renderer/core/EventBeat.h>
#include <react/renderer/core/EventEmitter.h>
#include <react/renderer/core/conversions.h>
#include <react/renderer/debug/SystraceSection.h>
#include <react/renderer/scheduler/Scheduler.h>
#include <react/renderer/scheduler/SchedulerDelegate.h>
#include <react/renderer/scheduler/SchedulerToolbox.h>
#include <react/renderer/uimanager/primitives.h>
#include <react/utils/ContextContainer.h>
// Included to set BaseTextProps config; can be deleted later.
#include <react/renderer/components/text/BaseTextProps.h>
#include <glog/logging.h>
using namespace facebook::jni;
using namespace facebook::jsi;
namespace facebook {
namespace react {
jni::local_ref<Binding::jhybriddata> Binding::initHybrid(
jni::alias_ref<jclass>) {
return makeCxxInstance();
}
// Thread-safe getter
std::shared_ptr<Scheduler> Binding::getScheduler() {
std::shared_lock<butter::shared_mutex> lock(installMutex_);
return scheduler_;
}
jni::local_ref<ReadableNativeMap::jhybridobject>
Binding::getInspectorDataForInstance(
jni::alias_ref<EventEmitterWrapper::javaobject> eventEmitterWrapper) {
std::shared_ptr<Scheduler> scheduler = getScheduler();
if (!scheduler) {
LOG(ERROR) << "Binding::startSurface: scheduler disappeared";
return ReadableNativeMap::newObjectCxxArgs(folly::dynamic::object());
}
EventEmitterWrapper *cEventEmitter = cthis(eventEmitterWrapper);
InspectorData data =
scheduler->getInspectorDataForInstance(*cEventEmitter->eventEmitter);
folly::dynamic result = folly::dynamic::object;
result["fileName"] = data.fileName;
result["lineNumber"] = data.lineNumber;
result["columnNumber"] = data.columnNumber;
result["selectedIndex"] = data.selectedIndex;
result["props"] = data.props;
auto hierarchy = folly::dynamic::array();
for (const auto &hierarchyItem : data.hierarchy) {
hierarchy.push_back(hierarchyItem);
}
result["hierarchy"] = hierarchy;
return ReadableNativeMap::newObjectCxxArgs(result);
}
constexpr static auto ReactFeatureFlagsJavaDescriptor =
"com/facebook/react/config/ReactFeatureFlags";
static bool getFeatureFlagValue(const char *name) {
static const auto reactFeatureFlagsJavaDescriptor =
jni::findClassStatic(ReactFeatureFlagsJavaDescriptor);
const auto field =
reactFeatureFlagsJavaDescriptor->getStaticField<jboolean>(name);
return reactFeatureFlagsJavaDescriptor->getStaticFieldValue(field);
}
void Binding::setPixelDensity(float pointScaleFactor) {
pointScaleFactor_ = pointScaleFactor;
}
void Binding::driveCxxAnimations() {
scheduler_->animationTick();
}
#pragma mark - Surface management
void Binding::startSurface(
jint surfaceId,
jni::alias_ref<jstring> moduleName,
NativeMap *initialProps) {
SystraceSection s("FabricUIManagerBinding::startSurface");
std::shared_ptr<Scheduler> scheduler = getScheduler();
if (!scheduler) {
LOG(ERROR) << "Binding::startSurface: scheduler disappeared";
return;
}
auto layoutContext = LayoutContext{};
layoutContext.pointScaleFactor = pointScaleFactor_;
auto surfaceHandler = SurfaceHandler{moduleName->toStdString(), surfaceId};
surfaceHandler.setContextContainer(scheduler->getContextContainer());
surfaceHandler.setProps(initialProps->consume());
surfaceHandler.constraintLayout({}, layoutContext);
scheduler->registerSurface(surfaceHandler);
surfaceHandler.start();
surfaceHandler.getMountingCoordinator()->setMountingOverrideDelegate(
animationDriver_);
{
SystraceSection s2("FabricUIManagerBinding::startSurface::surfaceId::lock");
std::unique_lock<butter::shared_mutex> lock(surfaceHandlerRegistryMutex_);
SystraceSection s3("FabricUIManagerBinding::startSurface::surfaceId");
surfaceHandlerRegistry_.emplace(surfaceId, std::move(surfaceHandler));
}
auto mountingManager =
verifyMountingManager("FabricUIManagerBinding::startSurface");
if (!mountingManager) {
return;
}
mountingManager->onSurfaceStart(surfaceId);
}
void Binding::startSurfaceWithConstraints(
jint surfaceId,
jni::alias_ref<jstring> moduleName,
NativeMap *initialProps,
jfloat minWidth,
jfloat maxWidth,
jfloat minHeight,
jfloat maxHeight,
jfloat offsetX,
jfloat offsetY,
jboolean isRTL,
jboolean doLeftAndRightSwapInRTL) {
SystraceSection s("FabricUIManagerBinding::startSurfaceWithConstraints");
if (enableFabricLogs_) {
LOG(WARNING)
<< "Binding::startSurfaceWithConstraints() was called (address: "
<< this << ", surfaceId: " << surfaceId << ").";
}
std::shared_ptr<Scheduler> scheduler = getScheduler();
if (!scheduler) {
LOG(ERROR) << "Binding::startSurfaceWithConstraints: scheduler disappeared";
return;
}
auto minimumSize =
Size{minWidth / pointScaleFactor_, minHeight / pointScaleFactor_};
auto maximumSize =
Size{maxWidth / pointScaleFactor_, maxHeight / pointScaleFactor_};
LayoutContext context;
context.viewportOffset =
Point{offsetX / pointScaleFactor_, offsetY / pointScaleFactor_};
context.pointScaleFactor = {pointScaleFactor_};
context.swapLeftAndRightInRTL = doLeftAndRightSwapInRTL;
LayoutConstraints constraints = {};
constraints.minimumSize = minimumSize;
constraints.maximumSize = maximumSize;
constraints.layoutDirection =
isRTL ? LayoutDirection::RightToLeft : LayoutDirection::LeftToRight;
auto surfaceHandler = SurfaceHandler{moduleName->toStdString(), surfaceId};
surfaceHandler.setContextContainer(scheduler_->getContextContainer());
surfaceHandler.setProps(initialProps->consume());
surfaceHandler.constraintLayout(constraints, context);
scheduler->registerSurface(surfaceHandler);
surfaceHandler.start();
surfaceHandler.getMountingCoordinator()->setMountingOverrideDelegate(
animationDriver_);
{
SystraceSection s2(
"FabricUIManagerBinding::startSurfaceWithConstraints::surfaceId::lock");
std::unique_lock<butter::shared_mutex> lock(surfaceHandlerRegistryMutex_);
SystraceSection s3(
"FabricUIManagerBinding::startSurfaceWithConstraints::surfaceId");
surfaceHandlerRegistry_.emplace(surfaceId, std::move(surfaceHandler));
}
auto mountingManager = verifyMountingManager(
"FabricUIManagerBinding::startSurfaceWithConstraints");
if (!mountingManager) {
return;
}
mountingManager->onSurfaceStart(surfaceId);
}
void Binding::renderTemplateToSurface(jint surfaceId, jstring uiTemplate) {
SystraceSection s("FabricUIManagerBinding::renderTemplateToSurface");
std::shared_ptr<Scheduler> scheduler = getScheduler();
if (!scheduler) {
LOG(ERROR) << "Binding::renderTemplateToSurface: scheduler disappeared";
return;
}
auto env = Environment::current();
const char *nativeString = env->GetStringUTFChars(uiTemplate, JNI_FALSE);
scheduler->renderTemplateToSurface(surfaceId, nativeString);
env->ReleaseStringUTFChars(uiTemplate, nativeString);
}
void Binding::stopSurface(jint surfaceId) {
SystraceSection s("FabricUIManagerBinding::stopSurface");
if (enableFabricLogs_) {
LOG(WARNING) << "Binding::stopSurface() was called (address: " << this
<< ", surfaceId: " << surfaceId << ").";
}
std::shared_ptr<Scheduler> scheduler = getScheduler();
if (!scheduler) {
LOG(ERROR) << "Binding::stopSurface: scheduler disappeared";
return;
}
{
std::unique_lock<butter::shared_mutex> lock(surfaceHandlerRegistryMutex_);
auto iterator = surfaceHandlerRegistry_.find(surfaceId);
if (iterator == surfaceHandlerRegistry_.end()) {
LOG(ERROR) << "Binding::stopSurface: Surface with given id is not found";
return;
}
auto surfaceHandler = std::move(iterator->second);
surfaceHandlerRegistry_.erase(iterator);
surfaceHandler.stop();
scheduler->unregisterSurface(surfaceHandler);
}
auto mountingManager =
verifyMountingManager("FabricUIManagerBinding::stopSurface");
if (!mountingManager) {
return;
}
mountingManager->onSurfaceStop(surfaceId);
}
void Binding::registerSurface(SurfaceHandlerBinding *surfaceHandlerBinding) {
auto const &surfaceHandler = surfaceHandlerBinding->getSurfaceHandler();
auto scheduler = getScheduler();
if (!scheduler) {
LOG(ERROR) << "Binding::registerSurface: scheduler disappeared";
return;
}
scheduler->registerSurface(surfaceHandler);
auto mountingManager =
verifyMountingManager("FabricUIManagerBinding::registerSurface");
if (!mountingManager) {
return;
}
mountingManager->onSurfaceStart(surfaceHandler.getSurfaceId());
}
void Binding::unregisterSurface(SurfaceHandlerBinding *surfaceHandlerBinding) {
auto const &surfaceHandler = surfaceHandlerBinding->getSurfaceHandler();
auto scheduler = getScheduler();
if (!scheduler) {
LOG(ERROR) << "Binding::unregisterSurface: scheduler disappeared";
return;
}
scheduler->unregisterSurface(surfaceHandler);
auto mountingManager =
verifyMountingManager("FabricUIManagerBinding::unregisterSurface");
if (!mountingManager) {
return;
}
mountingManager->onSurfaceStop(surfaceHandler.getSurfaceId());
}
void Binding::setConstraints(
jint surfaceId,
jfloat minWidth,
jfloat maxWidth,
jfloat minHeight,
jfloat maxHeight,
jfloat offsetX,
jfloat offsetY,
jboolean isRTL,
jboolean doLeftAndRightSwapInRTL) {
SystraceSection s("FabricUIManagerBinding::setConstraints");
std::shared_ptr<Scheduler> scheduler = getScheduler();
if (!scheduler) {
LOG(ERROR) << "Binding::setConstraints: scheduler disappeared";
return;
}
auto minimumSize =
Size{minWidth / pointScaleFactor_, minHeight / pointScaleFactor_};
auto maximumSize =
Size{maxWidth / pointScaleFactor_, maxHeight / pointScaleFactor_};
LayoutContext context;
context.viewportOffset =
Point{offsetX / pointScaleFactor_, offsetY / pointScaleFactor_};
context.pointScaleFactor = {pointScaleFactor_};
context.swapLeftAndRightInRTL = doLeftAndRightSwapInRTL;
LayoutConstraints constraints = {};
constraints.minimumSize = minimumSize;
constraints.maximumSize = maximumSize;
constraints.layoutDirection =
isRTL ? LayoutDirection::RightToLeft : LayoutDirection::LeftToRight;
{
std::shared_lock<butter::shared_mutex> lock(surfaceHandlerRegistryMutex_);
auto iterator = surfaceHandlerRegistry_.find(surfaceId);
if (iterator == surfaceHandlerRegistry_.end()) {
LOG(ERROR)
<< "Binding::setConstraints: Surface with given id is not found";
return;
}
auto &surfaceHandler = iterator->second;
surfaceHandler.constraintLayout(constraints, context);
}
}
#pragma mark - Install/uninstall java binding
void Binding::installFabricUIManager(
jni::alias_ref<JRuntimeExecutor::javaobject> runtimeExecutorHolder,
jni::alias_ref<JRuntimeScheduler::javaobject> runtimeSchedulerHolder,
jni::alias_ref<jobject> javaUIManager,
EventBeatManager *eventBeatManager,
ComponentFactory *componentsRegistry,
jni::alias_ref<jobject> reactNativeConfig) {
SystraceSection s("FabricUIManagerBinding::installFabricUIManager");
std::shared_ptr<const ReactNativeConfig> config =
std::make_shared<const ReactNativeConfigHolder>(reactNativeConfig);
enableFabricLogs_ =
config->getBool("react_fabric:enabled_android_fabric_logs");
disableRevisionCheckForPreallocation_ =
config->getBool("react_fabric:disable_revision_check_for_preallocation");
disablePreallocationOnClone_ =
getFeatureFlagValue("disablePreallocationOnClone");
if (enableFabricLogs_) {
LOG(WARNING) << "Binding::installFabricUIManager() was called (address: "
<< this << ").";
}
// Use std::lock and std::adopt_lock to prevent deadlocks by locking mutexes
// at the same time
std::unique_lock<butter::shared_mutex> lock(installMutex_);
auto globalJavaUiManager = make_global(javaUIManager);
mountingManager_ =
std::make_shared<FabricMountingManager>(config, globalJavaUiManager);
ContextContainer::Shared contextContainer =
std::make_shared<ContextContainer>();
auto runtimeExecutor = runtimeExecutorHolder->cthis()->get();
if (runtimeSchedulerHolder) {
auto runtimeScheduler = runtimeSchedulerHolder->cthis()->get().lock();
if (runtimeScheduler) {
runtimeExecutor =
[runtimeScheduler](
std::function<void(jsi::Runtime & runtime)> &&callback) {
runtimeScheduler->scheduleWork(std::move(callback));
};
contextContainer->insert(
"RuntimeScheduler",
std::weak_ptr<RuntimeScheduler>(runtimeScheduler));
}
}
// TODO: T31905686 Create synchronous Event Beat
EventBeat::Factory synchronousBeatFactory =
[eventBeatManager, runtimeExecutor, globalJavaUiManager](
EventBeat::SharedOwnerBox const &ownerBox)
-> std::unique_ptr<EventBeat> {
return std::make_unique<AsyncEventBeat>(
ownerBox, eventBeatManager, runtimeExecutor, globalJavaUiManager);
};
EventBeat::Factory asynchronousBeatFactory =
[eventBeatManager, runtimeExecutor, globalJavaUiManager](
EventBeat::SharedOwnerBox const &ownerBox)
-> std::unique_ptr<EventBeat> {
return std::make_unique<AsyncEventBeat>(
ownerBox, eventBeatManager, runtimeExecutor, globalJavaUiManager);
};
contextContainer->insert("ReactNativeConfig", config);
contextContainer->insert("FabricUIManager", globalJavaUiManager);
// Keep reference to config object and cache some feature flags here
reactNativeConfig_ = config;
contextContainer->insert(
"MapBufferSerializationEnabled",
getFeatureFlagValue("mapBufferSerializationEnabled"));
contextContainer->insert(
"CalculateTransformedFramesEnabled",
getFeatureFlagValue("calculateTransformedFramesEnabled"));
disablePreallocateViews_ = reactNativeConfig_->getBool(
"react_fabric:disabled_view_preallocation_android");
dispatchPreallocationInBackground_ = reactNativeConfig_->getBool(
"react_native_new_architecture:dispatch_preallocation_in_bg");
contextContainer->insert(
"EnableLargeTextMeasureCache",
getFeatureFlagValue("enableLargeTextMeasureCache"));
// Props setter pattern feature
Props::enablePropIteratorSetter =
getFeatureFlagValue("enableCppPropsIteratorSetter");
AccessibilityProps::enablePropIteratorSetter =
Props::enablePropIteratorSetter;
BaseTextProps::enablePropIteratorSetter = Props::enablePropIteratorSetter;
// RemoveDelete mega-op
ShadowViewMutation::PlatformSupportsRemoveDeleteTreeInstruction =
getFeatureFlagValue("enableRemoveDeleteTreeInstruction");
auto toolbox = SchedulerToolbox{};
toolbox.contextContainer = contextContainer;
toolbox.componentRegistryFactory = componentsRegistry->buildRegistryFunction;
toolbox.runtimeExecutor = runtimeExecutor;
toolbox.synchronousEventBeatFactory = synchronousBeatFactory;
toolbox.asynchronousEventBeatFactory = asynchronousBeatFactory;
backgroundExecutor_ = JBackgroundExecutor::create("fabric_bg");
toolbox.backgroundExecutor = backgroundExecutor_;
animationDriver_ = std::make_shared<LayoutAnimationDriver>(
runtimeExecutor, contextContainer, this);
scheduler_ =
std::make_shared<Scheduler>(toolbox, animationDriver_.get(), this);
}
void Binding::uninstallFabricUIManager() {
if (enableFabricLogs_) {
LOG(WARNING) << "Binding::uninstallFabricUIManager() was called (address: "
<< this << ").";
}
std::unique_lock<butter::shared_mutex> lock(installMutex_);
animationDriver_ = nullptr;
scheduler_ = nullptr;
mountingManager_ = nullptr;
reactNativeConfig_ = nullptr;
}
std::shared_ptr<FabricMountingManager> Binding::verifyMountingManager(
std::string const &hint) {
std::shared_lock<butter::shared_mutex> lock(installMutex_);
if (!mountingManager_) {
LOG(ERROR) << hint << " mounting manager disappeared.";
}
return mountingManager_;
}
void Binding::schedulerDidFinishTransaction(
MountingCoordinator::Shared const &mountingCoordinator) {
auto mountingManager =
verifyMountingManager("Binding::schedulerDidFinishTransaction");
if (!mountingManager) {
return;
}
mountingManager->executeMount(mountingCoordinator);
}
void Binding::schedulerDidRequestPreliminaryViewAllocation(
const SurfaceId surfaceId,
const ShadowNode &shadowNode) {
if (disablePreallocateViews_) {
return;
}
if (!shadowNode.getTraits().check(ShadowNodeTraits::Trait::FormsView)) {
return;
}
preallocateView(surfaceId, shadowNode);
}
void Binding::schedulerDidCloneShadowNode(
SurfaceId surfaceId,
ShadowNode const &oldShadowNode,
ShadowNode const &newShadowNode) {
if (disablePreallocationOnClone_) {
return;
}
// This is only necessary if view preallocation was skipped during
// createShadowNode
// We may need to PreAllocate a ShadowNode at this point if this is the
// earliest point it is possible to do so:
// 1. The revision is exactly 1
// 2. At revision 0 (the old node), View Preallocation would have been skipped
if (!disableRevisionCheckForPreallocation_) {
if (newShadowNode.getProps()->revision != 1) {
return;
}
if (oldShadowNode.getProps()->revision != 0) {
return;
}
}
// If the new node is concrete and the old wasn't, we can preallocate
if (!oldShadowNode.getTraits().check(ShadowNodeTraits::Trait::FormsView) &&
newShadowNode.getTraits().check(ShadowNodeTraits::Trait::FormsView)) {
preallocateView(surfaceId, newShadowNode);
}
}
void Binding::preallocateView(
SurfaceId surfaceId,
ShadowNode const &shadowNode) {
auto shadowView = ShadowView(shadowNode);
auto preallocationFunction = [this,
surfaceId,
shadowView = std::move(shadowView)] {
auto mountingManager = verifyMountingManager("Binding::preallocateView");
if (!mountingManager) {
return;
}
mountingManager->preallocateShadowView(surfaceId, shadowView);
};
if (dispatchPreallocationInBackground_) {
backgroundExecutor_(preallocationFunction);
} else {
preallocationFunction();
}
}
void Binding::schedulerDidDispatchCommand(
const ShadowView &shadowView,
std::string const &commandName,
folly::dynamic const &args) {
auto mountingManager =
verifyMountingManager("Binding::schedulerDidDispatchCommand");
if (!mountingManager) {
return;
}
mountingManager->dispatchCommand(shadowView, commandName, args);
}
void Binding::schedulerDidSendAccessibilityEvent(
const ShadowView &shadowView,
std::string const &eventType) {
auto mountingManager =
verifyMountingManager("Binding::schedulerDidSendAccessibilityEvent");
if (!mountingManager) {
return;
}
mountingManager->sendAccessibilityEvent(shadowView, eventType);
}
void Binding::schedulerDidSetIsJSResponder(
ShadowView const &shadowView,
bool isJSResponder,
bool blockNativeResponder) {
auto mountingManager =
verifyMountingManager("Binding::schedulerDidSetIsJSResponder");
if (!mountingManager) {
return;
}
mountingManager->setIsJSResponder(
shadowView, isJSResponder, blockNativeResponder);
}
void Binding::onAnimationStarted() {
auto mountingManager = verifyMountingManager("Binding::onAnimationStarted");
if (!mountingManager) {
return;
}
mountingManager->onAnimationStarted();
}
void Binding::onAllAnimationsComplete() {
auto mountingManager = verifyMountingManager("Binding::onAnimationComplete");
if (!mountingManager) {
return;
}
mountingManager->onAllAnimationsComplete();
}
void Binding::registerNatives() {
registerHybrid({
makeNativeMethod("initHybrid", Binding::initHybrid),
makeNativeMethod(
"installFabricUIManager", Binding::installFabricUIManager),
makeNativeMethod("startSurface", Binding::startSurface),
makeNativeMethod(
"getInspectorDataForInstance", Binding::getInspectorDataForInstance),
makeNativeMethod(
"startSurfaceWithConstraints", Binding::startSurfaceWithConstraints),
makeNativeMethod(
"renderTemplateToSurface", Binding::renderTemplateToSurface),
makeNativeMethod("stopSurface", Binding::stopSurface),
makeNativeMethod("setConstraints", Binding::setConstraints),
makeNativeMethod("setPixelDensity", Binding::setPixelDensity),
makeNativeMethod("driveCxxAnimations", Binding::driveCxxAnimations),
makeNativeMethod(
"uninstallFabricUIManager", Binding::uninstallFabricUIManager),
makeNativeMethod("registerSurface", Binding::registerSurface),
makeNativeMethod("unregisterSurface", Binding::unregisterSurface),
});
}
} // namespace react
} // namespace facebook
@@ -1,161 +0,0 @@
/*
* Copyright (c) Meta Platforms, Inc. and 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 "FabricMountingManager.h"
#include <memory>
#include <mutex>
#include <fbjni/fbjni.h>
#include <react/jni/JRuntimeExecutor.h>
#include <react/jni/JRuntimeScheduler.h>
#include <react/jni/ReadableNativeMap.h>
#include <react/renderer/animations/LayoutAnimationDriver.h>
#include <react/renderer/scheduler/Scheduler.h>
#include <react/renderer/scheduler/SchedulerDelegate.h>
#include <react/renderer/uimanager/LayoutAnimationStatusDelegate.h>
#include "ComponentFactory.h"
#include "EventBeatManager.h"
#include "EventEmitterWrapper.h"
#include "SurfaceHandlerBinding.h"
namespace facebook {
namespace react {
class Instance;
class Binding : public jni::HybridClass<Binding>,
public SchedulerDelegate,
public LayoutAnimationStatusDelegate {
public:
constexpr static const char *const kJavaDescriptor =
"Lcom/facebook/react/fabric/Binding;";
static void registerNatives();
std::shared_ptr<Scheduler> getScheduler();
private:
void setConstraints(
jint surfaceId,
jfloat minWidth,
jfloat maxWidth,
jfloat minHeight,
jfloat maxHeight,
jfloat offsetX,
jfloat offsetY,
jboolean isRTL,
jboolean doLeftAndRightSwapInRTL);
jni::local_ref<ReadableNativeMap::jhybridobject> getInspectorDataForInstance(
jni::alias_ref<EventEmitterWrapper::javaobject> eventEmitterWrapper);
static jni::local_ref<jhybriddata> initHybrid(jni::alias_ref<jclass>);
void installFabricUIManager(
jni::alias_ref<JRuntimeExecutor::javaobject> runtimeExecutorHolder,
jni::alias_ref<JRuntimeScheduler::javaobject> runtimeSchedulerHolder,
jni::alias_ref<jobject> javaUIManager,
EventBeatManager *eventBeatManager,
ComponentFactory *componentsRegistry,
jni::alias_ref<jobject> reactNativeConfig);
void startSurface(
jint surfaceId,
jni::alias_ref<jstring> moduleName,
NativeMap *initialProps);
void startSurfaceWithConstraints(
jint surfaceId,
jni::alias_ref<jstring> moduleName,
NativeMap *initialProps,
jfloat minWidth,
jfloat maxWidth,
jfloat minHeight,
jfloat maxHeight,
jfloat offsetX,
jfloat offsetY,
jboolean isRTL,
jboolean doLeftAndRightSwapInRTL);
void renderTemplateToSurface(jint surfaceId, jstring uiTemplate);
void stopSurface(jint surfaceId);
void registerSurface(SurfaceHandlerBinding *surfaceHandler);
void unregisterSurface(SurfaceHandlerBinding *surfaceHandler);
void schedulerDidFinishTransaction(
MountingCoordinator::Shared const &mountingCoordinator) override;
void schedulerDidRequestPreliminaryViewAllocation(
const SurfaceId surfaceId,
const ShadowNode &shadowNode) override;
void schedulerDidCloneShadowNode(
SurfaceId surfaceId,
const ShadowNode &oldShadowNode,
const ShadowNode &newShadowNode) override;
void schedulerDidDispatchCommand(
const ShadowView &shadowView,
std::string const &commandName,
folly::dynamic const &args) override;
void schedulerDidSendAccessibilityEvent(
const ShadowView &shadowView,
std::string const &eventType) override;
void schedulerDidSetIsJSResponder(
ShadowView const &shadowView,
bool isJSResponder,
bool blockNativeResponder) override;
void preallocateView(SurfaceId surfaceId, ShadowNode const &shadowNode);
void setPixelDensity(float pointScaleFactor);
void driveCxxAnimations();
void uninstallFabricUIManager();
// Private member variables
butter::shared_mutex installMutex_;
std::shared_ptr<FabricMountingManager> mountingManager_;
std::shared_ptr<Scheduler> scheduler_;
std::shared_ptr<FabricMountingManager> verifyMountingManager(
std::string const &locationHint);
// LayoutAnimations
void onAnimationStarted() override;
void onAllAnimationsComplete() override;
std::shared_ptr<LayoutAnimationDriver> animationDriver_;
BackgroundExecutor backgroundExecutor_;
butter::map<SurfaceId, SurfaceHandler> surfaceHandlerRegistry_{};
butter::shared_mutex
surfaceHandlerRegistryMutex_; // Protects `surfaceHandlerRegistry_`.
float pointScaleFactor_ = 1;
std::shared_ptr<const ReactNativeConfig> reactNativeConfig_{nullptr};
bool disablePreallocateViews_{false};
bool enableFabricLogs_{false};
bool disableRevisionCheckForPreallocation_{false};
bool dispatchPreallocationInBackground_{false};
bool disablePreallocationOnClone_{false};
};
} // namespace react
} // namespace facebook
@@ -1,70 +0,0 @@
# Copyright (c) Meta Platforms, Inc. and affiliates.
#
# This source code is licensed under the MIT license found in the
# LICENSE file in the root directory of this source tree.
cmake_minimum_required(VERSION 3.13)
file(GLOB fabricjni_SRCS CONFIGURE_DEPENDS *.cpp)
add_library(
fabricjni
SHARED
${fabricjni_SRCS}
)
target_include_directories(fabricjni PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
target_link_libraries(
fabricjni
butter
fb
fbjni
folly_runtime
glog
glog_init
jsi
mapbufferjni
react_codegen_rncore
react_debug
react_render_animations
react_render_attributedstring
react_render_componentregistry
react_render_core
react_render_debug
react_render_graphics
react_render_imagemanager
react_render_mapbuffer
react_render_mounting
react_render_runtimescheduler
react_render_scheduler
react_render_telemetry
react_render_templateprocessor
react_render_textlayoutmanager
react_render_uimanager
react_utils
react_config
reactnativejni
rrc_image
rrc_modal
rrc_progressbar
rrc_root
rrc_scrollview
rrc_slider
rrc_switch
rrc_text
rrc_textinput
rrc_unimplementedview
rrc_view
yoga
)
target_compile_options(
fabricjni
PRIVATE
-DLOG_TAG=\"Fabric\"
-fexceptions
-frtti
-std=c++17
-Wall
)
@@ -1,31 +0,0 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#include "ComponentFactory.h"
#include <android/log.h>
#include <fbjni/fbjni.h>
#include <jsi/jsi.h>
#include <react/renderer/componentregistry/ComponentDescriptorRegistry.h>
using namespace facebook::jsi;
namespace facebook {
namespace react {
jni::local_ref<ComponentFactory::jhybriddata> ComponentFactory::initHybrid(
jni::alias_ref<jclass>) {
return makeCxxInstance();
}
void ComponentFactory::registerNatives() {
registerHybrid({
makeNativeMethod("initHybrid", ComponentFactory::initHybrid),
});
}
} // namespace react
} // namespace facebook
@@ -1,39 +0,0 @@
/*
* Copyright (c) Meta Platforms, Inc. and 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 <fbjni/fbjni.h>
#include <jsi/jsi.h>
#include <react/renderer/componentregistry/ComponentDescriptorRegistry.h>
#include <react/renderer/scheduler/Scheduler.h>
#include <react/utils/ContextContainer.h>
#include <mutex>
#include <unordered_set>
using namespace facebook::jsi;
namespace facebook {
namespace react {
class Instance;
class ComponentFactory : public jni::HybridClass<ComponentFactory> {
public:
constexpr static const char *const kJavaDescriptor =
"Lcom/facebook/react/fabric/ComponentFactory;";
static void registerNatives();
ComponentRegistryFactory buildRegistryFunction;
private:
static jni::local_ref<jhybriddata> initHybrid(jni::alias_ref<jclass>);
};
} // namespace react
} // namespace facebook
@@ -1,114 +0,0 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#include "CoreComponentsRegistry.h"
#include <android/log.h>
#include <fbjni/fbjni.h>
#include <react/renderer/componentregistry/ComponentDescriptorRegistry.h>
#include <react/renderer/components/androidswitch/AndroidSwitchComponentDescriptor.h>
#include <react/renderer/components/androidtextinput/AndroidTextInputComponentDescriptor.h>
#include <react/renderer/components/image/ImageComponentDescriptor.h>
#include <react/renderer/components/modal/ModalHostViewComponentDescriptor.h>
#include <react/renderer/components/progressbar/AndroidProgressBarComponentDescriptor.h>
#include <react/renderer/components/rncore/ComponentDescriptors.h>
#include <react/renderer/components/scrollview/ScrollViewComponentDescriptor.h>
#include <react/renderer/components/slider/SliderComponentDescriptor.h>
#include <react/renderer/components/text/ParagraphComponentDescriptor.h>
#include <react/renderer/components/text/RawTextComponentDescriptor.h>
#include <react/renderer/components/text/TextComponentDescriptor.h>
#include <react/renderer/components/view/ViewComponentDescriptor.h>
namespace facebook {
namespace react {
CoreComponentsRegistry::CoreComponentsRegistry(ComponentFactory *delegate)
: delegate_(delegate) {}
std::shared_ptr<ComponentDescriptorProviderRegistry const>
CoreComponentsRegistry::sharedProviderRegistry() {
static auto providerRegistry =
[]() -> std::shared_ptr<ComponentDescriptorProviderRegistry> {
auto providerRegistry =
std::make_shared<ComponentDescriptorProviderRegistry>();
providerRegistry->add(concreteComponentDescriptorProvider<
AndroidProgressBarComponentDescriptor>());
providerRegistry->add(concreteComponentDescriptorProvider<
AndroidSwipeRefreshLayoutComponentDescriptor>());
providerRegistry->add(concreteComponentDescriptorProvider<
ActivityIndicatorViewComponentDescriptor>());
providerRegistry->add(concreteComponentDescriptorProvider<
AndroidTextInputComponentDescriptor>());
providerRegistry->add(
concreteComponentDescriptorProvider<ViewComponentDescriptor>());
providerRegistry->add(
concreteComponentDescriptorProvider<ImageComponentDescriptor>());
providerRegistry->add(concreteComponentDescriptorProvider<
ModalHostViewComponentDescriptor>());
providerRegistry->add(concreteComponentDescriptorProvider<
AndroidSwitchComponentDescriptor>());
providerRegistry->add(
concreteComponentDescriptorProvider<TextComponentDescriptor>());
providerRegistry->add(
concreteComponentDescriptorProvider<RawTextComponentDescriptor>());
providerRegistry->add(
concreteComponentDescriptorProvider<SliderComponentDescriptor>());
providerRegistry->add(
concreteComponentDescriptorProvider<ScrollViewComponentDescriptor>());
providerRegistry->add(
concreteComponentDescriptorProvider<
AndroidHorizontalScrollContentViewComponentDescriptor>());
providerRegistry->add(
concreteComponentDescriptorProvider<ParagraphComponentDescriptor>());
providerRegistry->add(concreteComponentDescriptorProvider<
AndroidDrawerLayoutComponentDescriptor>());
return providerRegistry;
}();
return providerRegistry;
}
jni::local_ref<CoreComponentsRegistry::jhybriddata>
CoreComponentsRegistry::initHybrid(
jni::alias_ref<jclass>,
ComponentFactory *delegate) {
auto instance = makeCxxInstance(delegate);
// TODO T69453179: Codegen this file
auto buildRegistryFunction =
[](EventDispatcher::Weak const &eventDispatcher,
ContextContainer::Shared const &contextContainer)
-> ComponentDescriptorRegistry::Shared {
auto registry = CoreComponentsRegistry::sharedProviderRegistry()
->createComponentDescriptorRegistry(
{eventDispatcher, contextContainer});
auto mutableRegistry =
std::const_pointer_cast<ComponentDescriptorRegistry>(registry);
mutableRegistry->setFallbackComponentDescriptor(
std::make_shared<UnimplementedNativeViewComponentDescriptor>(
ComponentDescriptorParameters{
eventDispatcher, contextContainer, nullptr}));
return registry;
};
delegate->buildRegistryFunction = buildRegistryFunction;
return instance;
}
void CoreComponentsRegistry::registerNatives() {
registerHybrid({
makeNativeMethod("initHybrid", CoreComponentsRegistry::initHybrid),
});
}
} // namespace react
} // namespace facebook
@@ -1,42 +0,0 @@
/*
* Copyright (c) Meta Platforms, Inc. and 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 <fbjni/fbjni.h>
#include <react/renderer/componentregistry/ComponentDescriptorProviderRegistry.h>
#include <react/renderer/componentregistry/ComponentDescriptorRegistry.h>
#include "ComponentFactory.h"
namespace facebook {
namespace react {
class CoreComponentsRegistry
: public facebook::jni::HybridClass<CoreComponentsRegistry> {
public:
constexpr static auto kJavaDescriptor =
"Lcom/facebook/react/fabric/CoreComponentsRegistry;";
static void registerNatives();
explicit CoreComponentsRegistry(ComponentFactory *delegate);
static std::shared_ptr<ComponentDescriptorProviderRegistry const>
sharedProviderRegistry();
private:
friend HybridBase;
const ComponentFactory *delegate_;
static jni::local_ref<jhybriddata> initHybrid(
jni::alias_ref<jclass>,
ComponentFactory *delegate);
};
} // namespace react
} // namespace facebook
@@ -1,52 +0,0 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#include "EventBeatManager.h"
#include <fbjni/fbjni.h>
using namespace facebook::jni;
namespace facebook {
namespace react {
EventBeatManager::EventBeatManager(
jni::alias_ref<EventBeatManager::jhybriddata> jhybridobject)
: jhybridobject_(jhybridobject) {}
jni::local_ref<EventBeatManager::jhybriddata> EventBeatManager::initHybrid(
jni::alias_ref<EventBeatManager::jhybriddata> jhybridobject) {
return makeCxxInstance(jhybridobject);
}
void EventBeatManager::addObserver(
EventBeatManagerObserver const &observer) const {
std::lock_guard<std::mutex> lock(mutex_);
observers_.insert(&observer);
}
void EventBeatManager::removeObserver(
EventBeatManagerObserver const &observer) const {
std::lock_guard<std::mutex> lock(mutex_);
observers_.erase(&observer);
}
void EventBeatManager::tick() {
std::lock_guard<std::mutex> lock(mutex_);
for (auto observer : observers_) {
observer->tick();
}
}
void EventBeatManager::registerNatives() {
registerHybrid({
makeNativeMethod("initHybrid", EventBeatManager::initHybrid),
makeNativeMethod("tick", EventBeatManager::tick),
});
}
} // namespace react
} // namespace facebook
@@ -1,67 +0,0 @@
/*
* Copyright (c) Meta Platforms, Inc. and 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 <mutex>
#include <unordered_set>
#include <ReactCommon/RuntimeExecutor.h>
#include <fbjni/fbjni.h>
#include <react/renderer/core/EventBeat.h>
namespace facebook {
namespace react {
class EventBeatManagerObserver {
public:
/*
* Called by `EventBeatManager` on the main thread signaling that this is a
* good time to flush an event queue.
*/
virtual void tick() const = 0;
virtual ~EventBeatManagerObserver() noexcept = default;
};
class EventBeatManager : public jni::HybridClass<EventBeatManager> {
public:
constexpr static const char *const kJavaDescriptor =
"Lcom/facebook/react/fabric/events/EventBeatManager;";
static void registerNatives();
explicit EventBeatManager(
jni::alias_ref<EventBeatManager::jhybriddata> jhybridobject);
/*
* Adds (or removes) observers.
* `EventBeatManager` does not own/retain observers; observers must overlive
* the manager or be properly removed before deallocation.
*/
void addObserver(EventBeatManagerObserver const &observer) const;
void removeObserver(EventBeatManagerObserver const &observer) const;
private:
/*
* Called by Java counterpart at the end of every run loop tick.
*/
void tick();
jni::alias_ref<EventBeatManager::jhybriddata> jhybridobject_;
mutable std::unordered_set<EventBeatManagerObserver const *>
observers_{}; // Protected by `mutex_`
mutable std::mutex mutex_;
static jni::local_ref<EventBeatManager::jhybriddata> initHybrid(
jni::alias_ref<EventBeatManager::jhybriddata> jhybridobject);
};
} // namespace react
} // namespace facebook
@@ -1,60 +0,0 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#include "EventEmitterWrapper.h"
#include <fbjni/fbjni.h>
using namespace facebook::jni;
namespace facebook {
namespace react {
jni::local_ref<EventEmitterWrapper::jhybriddata>
EventEmitterWrapper::initHybrid(jni::alias_ref<jclass>) {
return makeCxxInstance();
}
void EventEmitterWrapper::invokeEvent(
std::string eventName,
NativeMap *payload,
int category) {
// It is marginal, but possible for this to be constructed without a valid
// EventEmitter. In those cases, make sure we noop/blackhole events instead of
// crashing.
if (eventEmitter != nullptr) {
eventEmitter->dispatchEvent(
eventName,
payload->consume(),
EventPriority::AsynchronousBatched,
static_cast<RawEvent::Category>(category));
}
}
void EventEmitterWrapper::invokeUniqueEvent(
std::string eventName,
NativeMap *payload,
int customCoalesceKey) {
// TODO: customCoalesceKey currently unused
// It is marginal, but possible for this to be constructed without a valid
// EventEmitter. In those cases, make sure we noop/blackhole events instead of
// crashing.
if (eventEmitter != nullptr) {
eventEmitter->dispatchUniqueEvent(eventName, payload->consume());
}
}
void EventEmitterWrapper::registerNatives() {
registerHybrid({
makeNativeMethod("initHybrid", EventEmitterWrapper::initHybrid),
makeNativeMethod("invokeEvent", EventEmitterWrapper::invokeEvent),
makeNativeMethod(
"invokeUniqueEvent", EventEmitterWrapper::invokeUniqueEvent),
});
}
} // namespace react
} // namespace facebook
@@ -1,39 +0,0 @@
/*
* Copyright (c) Meta Platforms, Inc. and 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 <fbjni/fbjni.h>
#include <react/jni/ReadableNativeMap.h>
#include <react/renderer/core/EventEmitter.h>
namespace facebook {
namespace react {
class Instance;
class EventEmitterWrapper : public jni::HybridClass<EventEmitterWrapper> {
public:
constexpr static const char *const kJavaDescriptor =
"Lcom/facebook/react/fabric/events/EventEmitterWrapper;";
static void registerNatives();
SharedEventEmitter eventEmitter;
void invokeEvent(std::string eventName, NativeMap *params, int category);
void invokeUniqueEvent(
std::string eventName,
NativeMap *params,
int customCoalesceKey);
private:
static jni::local_ref<jhybriddata> initHybrid(jni::alias_ref<jclass>);
};
} // namespace react
} // namespace facebook
@@ -1,66 +0,0 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#include "FabricMountItem.h"
namespace facebook {
namespace react {
CppMountItem CppMountItem::CreateMountItem(ShadowView const &shadowView) {
return {CppMountItem::Type::Create, {}, {}, shadowView, -1};
}
CppMountItem CppMountItem::DeleteMountItem(ShadowView const &shadowView) {
return {CppMountItem::Type::Delete, {}, shadowView, {}, -1};
}
CppMountItem CppMountItem::InsertMountItem(
ShadowView const &parentView,
ShadowView const &shadowView,
int index) {
return {CppMountItem::Type::Insert, parentView, {}, shadowView, index};
}
CppMountItem CppMountItem::RemoveMountItem(
ShadowView const &parentView,
ShadowView const &shadowView,
int index) {
return {CppMountItem::Type::Remove, parentView, shadowView, {}, index};
}
CppMountItem CppMountItem::RemoveDeleteTreeMountItem(
ShadowView const &parentView,
ShadowView const &shadowView,
int index) {
return {
CppMountItem::Type::RemoveDeleteTree, parentView, shadowView, {}, index};
}
CppMountItem CppMountItem::UpdatePropsMountItem(
ShadowView const &oldShadowView,
ShadowView const &newShadowView) {
return {
CppMountItem::Type::UpdateProps, {}, oldShadowView, newShadowView, -1};
}
CppMountItem CppMountItem::UpdateStateMountItem(ShadowView const &shadowView) {
return {CppMountItem::Type::UpdateState, {}, {}, shadowView, -1};
}
CppMountItem CppMountItem::UpdateLayoutMountItem(
ShadowView const &shadowView,
ShadowView const &parentView) {
return {CppMountItem::Type::UpdateLayout, parentView, {}, shadowView, -1};
}
CppMountItem CppMountItem::UpdateEventEmitterMountItem(
ShadowView const &shadowView) {
return {CppMountItem::Type::UpdateEventEmitter, {}, {}, shadowView, -1};
}
CppMountItem CppMountItem::UpdatePaddingMountItem(
ShadowView const &shadowView) {
return {CppMountItem::Type::UpdatePadding, {}, {}, shadowView, -1};
}
CppMountItem CppMountItem::UpdateOverflowInsetMountItem(
ShadowView const &shadowView) {
return {CppMountItem::Type::UpdateOverflowInset, {}, {}, shadowView, -1};
}
} // namespace react
} // namespace facebook
@@ -1,88 +0,0 @@
/*
* Copyright (c) Meta Platforms, Inc. and 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 <fbjni/fbjni.h>
#include <react/renderer/mounting/ShadowView.h>
namespace facebook {
namespace react {
struct JMountItem : public jni::JavaClass<JMountItem> {
static constexpr auto kJavaDescriptor =
"Lcom/facebook/react/fabric/mounting/mountitems/MountItem;";
};
struct CppMountItem final {
#pragma mark - Designated Initializers
static CppMountItem CreateMountItem(ShadowView const &shadowView);
static CppMountItem DeleteMountItem(ShadowView const &shadowView);
static CppMountItem InsertMountItem(
ShadowView const &parentView,
ShadowView const &shadowView,
int index);
static CppMountItem RemoveMountItem(
ShadowView const &parentView,
ShadowView const &shadowView,
int index);
static CppMountItem RemoveDeleteTreeMountItem(
ShadowView const &parentView,
ShadowView const &shadowView,
int index);
static CppMountItem UpdatePropsMountItem(
ShadowView const &oldShadowView,
ShadowView const &newShadowView);
static CppMountItem UpdateStateMountItem(ShadowView const &shadowView);
static CppMountItem UpdateLayoutMountItem(
ShadowView const &shadowView,
ShadowView const &parentView);
static CppMountItem UpdateEventEmitterMountItem(ShadowView const &shadowView);
static CppMountItem UpdatePaddingMountItem(ShadowView const &shadowView);
static CppMountItem UpdateOverflowInsetMountItem(
ShadowView const &shadowView);
#pragma mark - Type
enum Type {
Undefined = -1,
Multiple = 1,
Create = 2,
Delete = 4,
Insert = 8,
Remove = 16,
UpdateProps = 32,
UpdateState = 64,
UpdateLayout = 128,
UpdateEventEmitter = 256,
UpdatePadding = 512,
UpdateOverflowInset = 1024,
RemoveDeleteTree = 2048,
};
#pragma mark - Fields
Type type = {Create};
ShadowView parentShadowView = {};
ShadowView oldChildShadowView = {};
ShadowView newChildShadowView = {};
int index = {};
};
} // namespace react
} // namespace facebook
@@ -1,978 +0,0 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#include "FabricMountingManager.h"
#include "EventEmitterWrapper.h"
#include "StateWrapperImpl.h"
#include "viewPropConversions.h"
#include <react/jni/ReadableNativeMap.h>
#include <react/renderer/components/scrollview/ScrollViewProps.h>
#include <react/renderer/core/conversions.h>
#include <react/renderer/debug/SystraceSection.h>
#include <react/renderer/mounting/ShadowViewMutation.h>
#include <fbjni/fbjni.h>
#include <glog/logging.h>
#include <cfenv>
#include <cmath>
#include <vector>
using namespace facebook::jni;
namespace facebook {
namespace react {
static bool getFeatureFlagValue(const char *name) {
static const auto reactFeatureFlagsJavaDescriptor = jni::findClassStatic(
FabricMountingManager::ReactFeatureFlagsJavaDescriptor);
const auto field =
reactFeatureFlagsJavaDescriptor->getStaticField<jboolean>(name);
return reactFeatureFlagsJavaDescriptor->getStaticFieldValue(field);
}
FabricMountingManager::FabricMountingManager(
std::shared_ptr<const ReactNativeConfig> &config,
global_ref<jobject> &javaUIManager)
: javaUIManager_(javaUIManager),
enableEarlyEventEmitterUpdate_(
config->getBool("react_fabric:enable_early_event_emitter_update")),
disablePreallocateViews_(
config->getBool("react_fabric:disabled_view_preallocation_android")),
disableRevisionCheckForPreallocation_(config->getBool(
"react_fabric:disable_revision_check_for_preallocation")),
useOverflowInset_(getFeatureFlagValue("useOverflowInset")),
shouldRememberAllocatedViews_(
getFeatureFlagValue("shouldRememberAllocatedViews")),
useMapBufferForViewProps_(config->getBool(
"react_native_new_architecture:use_mapbuffer_for_viewprops")) {}
void FabricMountingManager::onSurfaceStart(SurfaceId surfaceId) {
std::lock_guard lock(allocatedViewsMutex_);
allocatedViewRegistry_.emplace(surfaceId, butter::set<Tag>{});
}
void FabricMountingManager::onSurfaceStop(SurfaceId surfaceId) {
std::lock_guard lock(allocatedViewsMutex_);
allocatedViewRegistry_.erase(surfaceId);
}
static inline int getIntBufferSizeForType(CppMountItem::Type mountItemType) {
switch (mountItemType) {
case CppMountItem::Type::Create:
return 2; // tag, isLayoutable
case CppMountItem::Type::Insert:
case CppMountItem::Type::Remove:
return 3; // tag, parentTag, index
case CppMountItem::Type::RemoveDeleteTree:
return 3; // tag, parentTag, index
case CppMountItem::Type::Delete:
case CppMountItem::Type::UpdateProps:
case CppMountItem::Type::UpdateState:
case CppMountItem::Type::UpdateEventEmitter:
return 1; // tag
case CppMountItem::Type::UpdatePadding:
return 5; // tag, top, left, bottom, right
case CppMountItem::Type::UpdateLayout:
return 7; // tag, parentTag, x, y, w, h, DisplayType
case CppMountItem::Type::UpdateOverflowInset:
return 5; // tag, left, top, right, bottom
case CppMountItem::Undefined:
case CppMountItem::Multiple:
return -1;
}
}
static inline void updateBufferSizes(
CppMountItem::Type mountItemType,
int numInstructions,
int &batchMountItemIntsSize,
int &batchMountItemObjectsSize) {
if (numInstructions == 0) {
return;
}
batchMountItemIntsSize +=
numInstructions == 1 ? 1 : 2; // instructionType[, numInstructions]
batchMountItemIntsSize +=
numInstructions * getIntBufferSizeForType(mountItemType);
if (mountItemType == CppMountItem::Type::UpdateProps) {
batchMountItemObjectsSize +=
numInstructions; // props object * numInstructions
} else if (mountItemType == CppMountItem::Type::UpdateState) {
batchMountItemObjectsSize +=
numInstructions; // state object * numInstructions
} else if (mountItemType == CppMountItem::Type::UpdateEventEmitter) {
batchMountItemObjectsSize +=
numInstructions; // EventEmitter object * numInstructions
}
}
static inline void computeBufferSizes(
int &batchMountItemIntsSize,
int &batchMountItemObjectsSize,
std::vector<CppMountItem> &cppCommonMountItems,
std::vector<CppMountItem> &cppDeleteMountItems,
std::vector<CppMountItem> &cppUpdatePropsMountItems,
std::vector<CppMountItem> &cppUpdateStateMountItems,
std::vector<CppMountItem> &cppUpdatePaddingMountItems,
std::vector<CppMountItem> &cppUpdateLayoutMountItems,
std::vector<CppMountItem> &cppUpdateOverflowInsetMountItems,
std::vector<CppMountItem> &cppUpdateEventEmitterMountItems) {
CppMountItem::Type lastType = CppMountItem::Type::Undefined;
int numSameType = 0;
for (auto const &mountItem : cppCommonMountItems) {
const auto &mountItemType = mountItem.type;
if (lastType == mountItemType) {
numSameType++;
if (numSameType == 2) {
batchMountItemIntsSize += 1; // numInstructions
}
} else {
numSameType = 1;
lastType = mountItemType;
batchMountItemIntsSize += 1; // instructionType
}
batchMountItemIntsSize += getIntBufferSizeForType(mountItemType);
if (mountItemType == CppMountItem::Type::Create) {
batchMountItemObjectsSize +=
4; // component name, props, state, event emitter
}
}
updateBufferSizes(
CppMountItem::Type::UpdateProps,
cppUpdatePropsMountItems.size(),
batchMountItemIntsSize,
batchMountItemObjectsSize);
updateBufferSizes(
CppMountItem::Type::UpdateState,
cppUpdateStateMountItems.size(),
batchMountItemIntsSize,
batchMountItemObjectsSize);
updateBufferSizes(
CppMountItem::Type::UpdatePadding,
cppUpdatePaddingMountItems.size(),
batchMountItemIntsSize,
batchMountItemObjectsSize);
updateBufferSizes(
CppMountItem::Type::UpdateLayout,
cppUpdateLayoutMountItems.size(),
batchMountItemIntsSize,
batchMountItemObjectsSize);
updateBufferSizes(
CppMountItem::Type::UpdateOverflowInset,
cppUpdateOverflowInsetMountItems.size(),
batchMountItemIntsSize,
batchMountItemObjectsSize);
updateBufferSizes(
CppMountItem::Type::UpdateEventEmitter,
cppUpdateEventEmitterMountItems.size(),
batchMountItemIntsSize,
batchMountItemObjectsSize);
updateBufferSizes(
CppMountItem::Type::Delete,
cppDeleteMountItems.size(),
batchMountItemIntsSize,
batchMountItemObjectsSize);
}
static inline void writeIntBufferTypePreamble(
int mountItemType,
int numItems,
_JNIEnv *env,
jintArray &intBufferArray,
int &intBufferPosition) {
jint temp[2];
if (numItems == 1) {
temp[0] = mountItemType;
env->SetIntArrayRegion(intBufferArray, intBufferPosition, 1, temp);
intBufferPosition += 1;
} else {
temp[0] = mountItemType | CppMountItem::Type::Multiple;
temp[1] = numItems;
env->SetIntArrayRegion(intBufferArray, intBufferPosition, 2, temp);
intBufferPosition += 2;
}
}
inline local_ref<ReadableArray::javaobject> castReadableArray(
local_ref<ReadableNativeArray::javaobject> const &nativeArray) {
return make_local(
reinterpret_cast<ReadableArray::javaobject>(nativeArray.get()));
}
// TODO: this method will be removed when binding for components are code-gen
local_ref<JString> getPlatformComponentName(ShadowView const &shadowView) {
static std::string scrollViewComponentName = std::string("ScrollView");
local_ref<JString> componentName;
if (scrollViewComponentName == shadowView.componentName) {
auto newViewProps =
std::static_pointer_cast<const ScrollViewProps>(shadowView.props);
if (newViewProps->getProbablyMoreHorizontalThanVertical_DEPRECATED()) {
componentName = make_jstring("AndroidHorizontalScrollView");
return componentName;
}
}
componentName = make_jstring(shadowView.componentName);
return componentName;
}
static inline float scale(Float value, Float pointScaleFactor) {
std::feclearexcept(FE_ALL_EXCEPT);
float result = value * pointScaleFactor;
if (std::fetestexcept(FE_OVERFLOW)) {
LOG(ERROR) << "Binding::scale - FE_OVERFLOW - value: " << value
<< " pointScaleFactor: " << pointScaleFactor
<< " result: " << result;
}
if (std::fetestexcept(FE_UNDERFLOW)) {
LOG(ERROR) << "Binding::scale - FE_UNDERFLOW - value: " << value
<< " pointScaleFactor: " << pointScaleFactor
<< " result: " << result;
}
return result;
}
local_ref<jobject> FabricMountingManager::getProps(
ShadowView const &oldShadowView,
ShadowView const &newShadowView) {
if (useMapBufferForViewProps_ &&
newShadowView.traits.check(ShadowNodeTraits::Trait::View)) {
react_native_assert(
newShadowView.props->rawProps.empty() &&
"Raw props must be empty when views are using mapbuffer");
auto oldProps = oldShadowView.props != nullptr
? static_cast<ViewProps const &>(*oldShadowView.props)
: ViewProps{};
auto newProps = static_cast<ViewProps const &>(*newShadowView.props);
return JReadableMapBuffer::createWithContents(
viewPropsDiff(oldProps, newProps));
} else {
return ReadableNativeMap::newObjectCxxArgs(newShadowView.props->rawProps);
}
}
void FabricMountingManager::executeMount(
MountingCoordinator::Shared const &mountingCoordinator) {
std::lock_guard<std::recursive_mutex> lock(commitMutex_);
SystraceSection s(
"FabricUIManagerBinding::schedulerDidFinishTransactionIntBuffer");
auto finishTransactionStartTime = telemetryTimePointNow();
auto mountingTransaction = mountingCoordinator->pullTransaction();
if (!mountingTransaction.has_value()) {
return;
}
auto env = Environment::current();
auto telemetry = mountingTransaction->getTelemetry();
auto surfaceId = mountingTransaction->getSurfaceId();
auto &mutations = mountingTransaction->getMutations();
auto revisionNumber = telemetry.getRevisionNumber();
std::vector<CppMountItem> cppCommonMountItems;
std::vector<CppMountItem> cppDeleteMountItems;
std::vector<CppMountItem> cppUpdatePropsMountItems;
std::vector<CppMountItem> cppUpdateStateMountItems;
std::vector<CppMountItem> cppUpdatePaddingMountItems;
std::vector<CppMountItem> cppUpdateLayoutMountItems;
std::vector<CppMountItem> cppUpdateOverflowInsetMountItems;
std::vector<CppMountItem> cppUpdateEventEmitterMountItems;
{
std::lock_guard allocatedViewsLock(allocatedViewsMutex_);
auto allocatedViewsIterator = allocatedViewRegistry_.find(surfaceId);
auto const &allocatedViewTags =
allocatedViewsIterator != allocatedViewRegistry_.end()
? allocatedViewsIterator->second
: butter::set<Tag>{};
if (allocatedViewsIterator == allocatedViewRegistry_.end()) {
LOG(ERROR) << "Executing commit after surface was stopped!";
}
bool noRevisionCheck =
disablePreallocateViews_ || disableRevisionCheckForPreallocation_;
for (const auto &mutation : mutations) {
const auto &parentShadowView = mutation.parentShadowView;
const auto &oldChildShadowView = mutation.oldChildShadowView;
const auto &newChildShadowView = mutation.newChildShadowView;
auto &mutationType = mutation.type;
auto &index = mutation.index;
bool isVirtual = mutation.mutatedViewIsVirtual();
switch (mutationType) {
case ShadowViewMutation::Create: {
bool revisionCheck =
noRevisionCheck || newChildShadowView.props->revision > 1;
bool allocationCheck =
!allocatedViewTags.contains(newChildShadowView.tag);
bool shouldCreateView =
shouldRememberAllocatedViews_ ? allocationCheck : revisionCheck;
if (shouldCreateView) {
cppCommonMountItems.push_back(
CppMountItem::CreateMountItem(newChildShadowView));
}
break;
}
case ShadowViewMutation::Remove: {
if (!isVirtual && !mutation.isRedundantOperation) {
cppCommonMountItems.push_back(CppMountItem::RemoveMountItem(
parentShadowView, oldChildShadowView, index));
}
break;
}
case ShadowViewMutation::RemoveDeleteTree: {
if (!isVirtual) {
cppCommonMountItems.push_back(
CppMountItem::RemoveDeleteTreeMountItem(
parentShadowView, oldChildShadowView, index));
}
break;
}
case ShadowViewMutation::Delete: {
if (!mutation.isRedundantOperation) {
cppDeleteMountItems.push_back(
CppMountItem::DeleteMountItem(oldChildShadowView));
}
break;
}
case ShadowViewMutation::Update: {
if (!isVirtual) {
if (oldChildShadowView.props != newChildShadowView.props) {
cppUpdatePropsMountItems.push_back(
CppMountItem::UpdatePropsMountItem(
oldChildShadowView, newChildShadowView));
}
if (oldChildShadowView.state != newChildShadowView.state) {
cppUpdateStateMountItems.push_back(
CppMountItem::UpdateStateMountItem(newChildShadowView));
}
// Padding: padding mountItems must be executed before layout props
// are updated in the view. This is necessary to ensure that events
// (resulting from layout changes) are dispatched with the correct
// padding information.
if (oldChildShadowView.layoutMetrics.contentInsets !=
newChildShadowView.layoutMetrics.contentInsets) {
cppUpdatePaddingMountItems.push_back(
CppMountItem::UpdatePaddingMountItem(newChildShadowView));
}
if (oldChildShadowView.layoutMetrics !=
newChildShadowView.layoutMetrics) {
cppUpdateLayoutMountItems.push_back(
CppMountItem::UpdateLayoutMountItem(
mutation.newChildShadowView, parentShadowView));
}
// OverflowInset: This is the values indicating boundaries including
// children of the current view. The layout of current view may not
// change, and we separate this part from layout mount items to not
// pack too much data there.
if (useOverflowInset_ &&
(oldChildShadowView.layoutMetrics.overflowInset !=
newChildShadowView.layoutMetrics.overflowInset)) {
cppUpdateOverflowInsetMountItems.push_back(
CppMountItem::UpdateOverflowInsetMountItem(
newChildShadowView));
}
}
if (oldChildShadowView.eventEmitter !=
newChildShadowView.eventEmitter) {
cppUpdateEventEmitterMountItems.push_back(
CppMountItem::UpdateEventEmitterMountItem(
mutation.newChildShadowView));
}
break;
}
case ShadowViewMutation::Insert: {
if (!isVirtual) {
// Insert item
cppCommonMountItems.push_back(CppMountItem::InsertMountItem(
parentShadowView, newChildShadowView, index));
bool revisionCheck =
noRevisionCheck || newChildShadowView.props->revision > 1;
bool allocationCheck =
allocatedViewTags.find(newChildShadowView.tag) ==
allocatedViewTags.end();
bool shouldCreateView =
shouldRememberAllocatedViews_ ? allocationCheck : revisionCheck;
if (shouldCreateView) {
cppUpdatePropsMountItems.push_back(
CppMountItem::UpdatePropsMountItem({}, newChildShadowView));
}
// State
if (newChildShadowView.state) {
cppUpdateStateMountItems.push_back(
CppMountItem::UpdateStateMountItem(newChildShadowView));
}
// Padding: padding mountItems must be executed before layout props
// are updated in the view. This is necessary to ensure that events
// (resulting from layout changes) are dispatched with the correct
// padding information.
if (newChildShadowView.layoutMetrics.contentInsets !=
EdgeInsets::ZERO) {
cppUpdatePaddingMountItems.push_back(
CppMountItem::UpdatePaddingMountItem(newChildShadowView));
}
// Layout
cppUpdateLayoutMountItems.push_back(
CppMountItem::UpdateLayoutMountItem(
newChildShadowView, parentShadowView));
// OverflowInset: This is the values indicating boundaries including
// children of the current view. The layout of current view may not
// change, and we separate this part from layout mount items to not
// pack too much data there.
if (useOverflowInset_ &&
newChildShadowView.layoutMetrics.overflowInset !=
EdgeInsets::ZERO) {
cppUpdateOverflowInsetMountItems.push_back(
CppMountItem::UpdateOverflowInsetMountItem(
newChildShadowView));
}
}
// EventEmitter
cppUpdateEventEmitterMountItems.push_back(
CppMountItem::UpdateEventEmitterMountItem(
mutation.newChildShadowView));
break;
}
default: {
break;
}
}
}
if (shouldRememberAllocatedViews_ &&
allocatedViewsIterator != allocatedViewRegistry_.end()) {
auto &views = allocatedViewsIterator->second;
for (auto const &mutation : mutations) {
switch (mutation.type) {
case ShadowViewMutation::Create:
views.insert(mutation.newChildShadowView.tag);
break;
case ShadowViewMutation::Delete:
views.erase(mutation.oldChildShadowView.tag);
break;
default:
break;
}
}
}
}
// We now have all the information we need, including ordering of mount items,
// to know exactly how much space must be allocated
int batchMountItemIntsSize = 0;
int batchMountItemObjectsSize = 0;
computeBufferSizes(
batchMountItemIntsSize,
batchMountItemObjectsSize,
cppCommonMountItems,
cppDeleteMountItems,
cppUpdatePropsMountItems,
cppUpdateStateMountItems,
cppUpdatePaddingMountItems,
cppUpdateLayoutMountItems,
cppUpdateOverflowInsetMountItems,
cppUpdateEventEmitterMountItems);
static auto createMountItemsIntBufferBatchContainer =
jni::findClassStatic(UIManagerJavaDescriptor)
->getMethod<alias_ref<JMountItem>(
jint, jintArray, jtypeArray<jobject>, jint)>(
"createIntBufferBatchMountItem");
static auto scheduleMountItem = jni::findClassStatic(UIManagerJavaDescriptor)
->getMethod<void(
JMountItem::javaobject,
jint,
jlong,
jlong,
jlong,
jlong,
jlong,
jlong,
jlong)>("scheduleMountItem");
if (batchMountItemIntsSize == 0) {
auto finishTransactionEndTime = telemetryTimePointNow();
scheduleMountItem(
javaUIManager_,
nullptr,
telemetry.getRevisionNumber(),
telemetryTimePointToMilliseconds(telemetry.getCommitStartTime()),
telemetryTimePointToMilliseconds(telemetry.getDiffStartTime()),
telemetryTimePointToMilliseconds(telemetry.getDiffEndTime()),
telemetryTimePointToMilliseconds(telemetry.getLayoutStartTime()),
telemetryTimePointToMilliseconds(telemetry.getLayoutEndTime()),
telemetryTimePointToMilliseconds(finishTransactionStartTime),
telemetryTimePointToMilliseconds(finishTransactionEndTime));
return;
}
// Allocate the intBuffer and object array, now that we know exact sizes
// necessary
jintArray intBufferArray = env->NewIntArray(batchMountItemIntsSize);
local_ref<JArrayClass<jobject>> objBufferArray =
JArrayClass<jobject>::newArray(batchMountItemObjectsSize);
// Fill in arrays
int intBufferPosition = 0;
int objBufferPosition = 0;
int prevMountItemType = -1;
jint temp[7];
for (int i = 0; i < cppCommonMountItems.size(); i++) {
const auto &mountItem = cppCommonMountItems[i];
const auto &mountItemType = mountItem.type;
// Get type here, and count forward how many items of this type are in a
// row. Write preamble to any common type here.
if (prevMountItemType != mountItemType) {
int numSameItemTypes = 1;
for (int j = i + 1; j < cppCommonMountItems.size() &&
cppCommonMountItems[j].type == mountItemType;
j++) {
numSameItemTypes++;
}
writeIntBufferTypePreamble(
mountItemType,
numSameItemTypes,
env,
intBufferArray,
intBufferPosition);
}
prevMountItemType = mountItemType;
// TODO: multi-create, multi-insert, etc
if (mountItemType == CppMountItem::Type::Create) {
local_ref<JString> componentName =
getPlatformComponentName(mountItem.newChildShadowView);
int isLayoutable =
mountItem.newChildShadowView.layoutMetrics != EmptyLayoutMetrics ? 1
: 0;
local_ref<JObject> props =
getProps(mountItem.oldChildShadowView, mountItem.newChildShadowView);
// Do not hold onto Java object from C
// We DO want to hold onto C object from Java, since we don't know the
// lifetime of the Java object
local_ref<StateWrapperImpl::JavaPart> javaStateWrapper = nullptr;
if (mountItem.newChildShadowView.state != nullptr) {
javaStateWrapper = StateWrapperImpl::newObjectJavaArgs();
StateWrapperImpl *cStateWrapper = cthis(javaStateWrapper);
cStateWrapper->state_ = mountItem.newChildShadowView.state;
}
// Do not hold a reference to javaEventEmitter from the C++ side.
SharedEventEmitter eventEmitter =
mountItem.newChildShadowView.eventEmitter;
auto javaEventEmitter = EventEmitterWrapper::newObjectJavaArgs();
EventEmitterWrapper *cEventEmitter = cthis(javaEventEmitter);
cEventEmitter->eventEmitter = eventEmitter;
temp[0] = mountItem.newChildShadowView.tag;
temp[1] = isLayoutable;
env->SetIntArrayRegion(intBufferArray, intBufferPosition, 2, temp);
intBufferPosition += 2;
(*objBufferArray)[objBufferPosition++] = componentName.get();
(*objBufferArray)[objBufferPosition++] = props.get();
(*objBufferArray)[objBufferPosition++] =
javaStateWrapper != nullptr ? javaStateWrapper.get() : nullptr;
(*objBufferArray)[objBufferPosition++] = javaEventEmitter.get();
} else if (mountItemType == CppMountItem::Type::Insert) {
temp[0] = mountItem.newChildShadowView.tag;
temp[1] = mountItem.parentShadowView.tag;
temp[2] = mountItem.index;
env->SetIntArrayRegion(intBufferArray, intBufferPosition, 3, temp);
intBufferPosition += 3;
} else if (mountItemType == CppMountItem::Remove) {
temp[0] = mountItem.oldChildShadowView.tag;
temp[1] = mountItem.parentShadowView.tag;
temp[2] = mountItem.index;
env->SetIntArrayRegion(intBufferArray, intBufferPosition, 3, temp);
intBufferPosition += 3;
} else if (mountItemType == CppMountItem::RemoveDeleteTree) {
temp[0] = mountItem.oldChildShadowView.tag;
temp[1] = mountItem.parentShadowView.tag;
temp[2] = mountItem.index;
env->SetIntArrayRegion(intBufferArray, intBufferPosition, 3, temp);
intBufferPosition += 3;
} else {
LOG(ERROR) << "Unexpected CppMountItem type";
}
}
if (!cppUpdatePropsMountItems.empty()) {
writeIntBufferTypePreamble(
CppMountItem::Type::UpdateProps,
cppUpdatePropsMountItems.size(),
env,
intBufferArray,
intBufferPosition);
for (const auto &mountItem : cppUpdatePropsMountItems) {
temp[0] = mountItem.newChildShadowView.tag;
env->SetIntArrayRegion(intBufferArray, intBufferPosition, 1, temp);
intBufferPosition += 1;
(*objBufferArray)[objBufferPosition++] =
getProps(mountItem.oldChildShadowView, mountItem.newChildShadowView);
}
}
if (!cppUpdateStateMountItems.empty()) {
writeIntBufferTypePreamble(
CppMountItem::Type::UpdateState,
cppUpdateStateMountItems.size(),
env,
intBufferArray,
intBufferPosition);
for (const auto &mountItem : cppUpdateStateMountItems) {
temp[0] = mountItem.newChildShadowView.tag;
env->SetIntArrayRegion(intBufferArray, intBufferPosition, 1, temp);
intBufferPosition += 1;
auto state = mountItem.newChildShadowView.state;
// Do not hold onto Java object from C
// We DO want to hold onto C object from Java, since we don't know the
// lifetime of the Java object
local_ref<StateWrapperImpl::JavaPart> javaStateWrapper = nullptr;
if (state != nullptr) {
javaStateWrapper = StateWrapperImpl::newObjectJavaArgs();
StateWrapperImpl *cStateWrapper = cthis(javaStateWrapper);
cStateWrapper->state_ = state;
}
(*objBufferArray)[objBufferPosition++] =
(javaStateWrapper != nullptr ? javaStateWrapper.get() : nullptr);
}
}
if (!cppUpdatePaddingMountItems.empty()) {
writeIntBufferTypePreamble(
CppMountItem::Type::UpdatePadding,
cppUpdatePaddingMountItems.size(),
env,
intBufferArray,
intBufferPosition);
for (const auto &mountItem : cppUpdatePaddingMountItems) {
auto layoutMetrics = mountItem.newChildShadowView.layoutMetrics;
auto pointScaleFactor = layoutMetrics.pointScaleFactor;
auto contentInsets = layoutMetrics.contentInsets;
int left = floor(scale(contentInsets.left, pointScaleFactor));
int top = floor(scale(contentInsets.top, pointScaleFactor));
int right = floor(scale(contentInsets.right, pointScaleFactor));
int bottom = floor(scale(contentInsets.bottom, pointScaleFactor));
temp[0] = mountItem.newChildShadowView.tag;
temp[1] = left;
temp[2] = top;
temp[3] = right;
temp[4] = bottom;
env->SetIntArrayRegion(intBufferArray, intBufferPosition, 5, temp);
intBufferPosition += 5;
}
}
if (!cppUpdateLayoutMountItems.empty()) {
writeIntBufferTypePreamble(
CppMountItem::Type::UpdateLayout,
cppUpdateLayoutMountItems.size(),
env,
intBufferArray,
intBufferPosition);
for (const auto &mountItem : cppUpdateLayoutMountItems) {
auto layoutMetrics = mountItem.newChildShadowView.layoutMetrics;
auto pointScaleFactor = layoutMetrics.pointScaleFactor;
auto frame = layoutMetrics.frame;
int x = round(scale(frame.origin.x, pointScaleFactor));
int y = round(scale(frame.origin.y, pointScaleFactor));
int w = round(scale(frame.size.width, pointScaleFactor));
int h = round(scale(frame.size.height, pointScaleFactor));
int displayType =
toInt(mountItem.newChildShadowView.layoutMetrics.displayType);
temp[0] = mountItem.newChildShadowView.tag;
temp[1] = mountItem.parentShadowView.tag;
temp[2] = x;
temp[3] = y;
temp[4] = w;
temp[5] = h;
temp[6] = displayType;
env->SetIntArrayRegion(intBufferArray, intBufferPosition, 7, temp);
intBufferPosition += 7;
}
}
if (!cppUpdateOverflowInsetMountItems.empty()) {
writeIntBufferTypePreamble(
CppMountItem::Type::UpdateOverflowInset,
cppUpdateOverflowInsetMountItems.size(),
env,
intBufferArray,
intBufferPosition);
for (const auto &mountItem : cppUpdateOverflowInsetMountItems) {
auto layoutMetrics = mountItem.newChildShadowView.layoutMetrics;
auto pointScaleFactor = layoutMetrics.pointScaleFactor;
auto overflowInset = layoutMetrics.overflowInset;
int overflowInsetLeft =
round(scale(overflowInset.left, pointScaleFactor));
int overflowInsetTop = round(scale(overflowInset.top, pointScaleFactor));
int overflowInsetRight =
round(scale(overflowInset.right, pointScaleFactor));
int overflowInsetBottom =
round(scale(overflowInset.bottom, pointScaleFactor));
temp[0] = mountItem.newChildShadowView.tag;
temp[1] = overflowInsetLeft;
temp[2] = overflowInsetTop;
temp[3] = overflowInsetRight;
temp[4] = overflowInsetBottom;
env->SetIntArrayRegion(intBufferArray, intBufferPosition, 5, temp);
intBufferPosition += 5;
}
}
if (!cppUpdateEventEmitterMountItems.empty()) {
writeIntBufferTypePreamble(
CppMountItem::Type::UpdateEventEmitter,
cppUpdateEventEmitterMountItems.size(),
env,
intBufferArray,
intBufferPosition);
for (const auto &mountItem : cppUpdateEventEmitterMountItems) {
temp[0] = mountItem.newChildShadowView.tag;
env->SetIntArrayRegion(intBufferArray, intBufferPosition, 1, temp);
intBufferPosition += 1;
SharedEventEmitter eventEmitter =
mountItem.newChildShadowView.eventEmitter;
// Do not hold a reference to javaEventEmitter from the C++ side.
auto javaEventEmitter = EventEmitterWrapper::newObjectJavaArgs();
EventEmitterWrapper *cEventEmitter = cthis(javaEventEmitter);
cEventEmitter->eventEmitter = eventEmitter;
(*objBufferArray)[objBufferPosition++] = javaEventEmitter.get();
}
}
// Write deletes last - so that all prop updates, etc, for the tag in the same
// batch don't fail. Without additional machinery, moving deletes here
// requires that the differ never produces "DELETE...CREATE" in that order for
// the same tag. It's nice to be able to batch all similar operations together
// for space efficiency.
if (!cppDeleteMountItems.empty()) {
writeIntBufferTypePreamble(
CppMountItem::Type::Delete,
cppDeleteMountItems.size(),
env,
intBufferArray,
intBufferPosition);
for (const auto &mountItem : cppDeleteMountItems) {
temp[0] = mountItem.oldChildShadowView.tag;
env->SetIntArrayRegion(intBufferArray, intBufferPosition, 1, temp);
intBufferPosition += 1;
}
}
// If there are no items, we pass a nullptr instead of passing the object
// through the JNI
auto batch = createMountItemsIntBufferBatchContainer(
javaUIManager_,
surfaceId,
batchMountItemIntsSize == 0 ? nullptr : intBufferArray,
batchMountItemObjectsSize == 0 ? nullptr : objBufferArray.get(),
revisionNumber);
auto finishTransactionEndTime = telemetryTimePointNow();
scheduleMountItem(
javaUIManager_,
batch.get(),
telemetry.getRevisionNumber(),
telemetryTimePointToMilliseconds(telemetry.getCommitStartTime()),
telemetryTimePointToMilliseconds(telemetry.getDiffStartTime()),
telemetryTimePointToMilliseconds(telemetry.getDiffEndTime()),
telemetryTimePointToMilliseconds(telemetry.getLayoutStartTime()),
telemetryTimePointToMilliseconds(telemetry.getLayoutEndTime()),
telemetryTimePointToMilliseconds(finishTransactionStartTime),
telemetryTimePointToMilliseconds(finishTransactionEndTime));
env->DeleteLocalRef(intBufferArray);
}
void FabricMountingManager::preallocateShadowView(
SurfaceId surfaceId,
ShadowView const &shadowView) {
if (shouldRememberAllocatedViews_) {
std::lock_guard lock(allocatedViewsMutex_);
auto allocatedViewsIterator = allocatedViewRegistry_.find(surfaceId);
if (allocatedViewsIterator == allocatedViewRegistry_.end()) {
return;
}
auto &allocatedViews = allocatedViewsIterator->second;
if (allocatedViews.find(shadowView.tag) != allocatedViews.end()) {
return;
}
allocatedViews.insert(shadowView.tag);
}
bool isLayoutableShadowNode = shadowView.layoutMetrics != EmptyLayoutMetrics;
static auto preallocateView =
jni::findClassStatic(UIManagerJavaDescriptor)
->getMethod<void(
jint, jint, jstring, jobject, jobject, jobject, jboolean)>(
"preallocateView");
// Do not hold onto Java object from C
// We DO want to hold onto C object from Java, since we don't know the
// lifetime of the Java object
local_ref<StateWrapperImpl::JavaPart> javaStateWrapper = nullptr;
if (shadowView.state != nullptr) {
javaStateWrapper = StateWrapperImpl::newObjectJavaArgs();
StateWrapperImpl *cStateWrapper = cthis(javaStateWrapper);
cStateWrapper->state_ = shadowView.state;
}
// Do not hold a reference to javaEventEmitter from the C++ side.
local_ref<EventEmitterWrapper::JavaPart> javaEventEmitter = nullptr;
if (enableEarlyEventEmitterUpdate_) {
SharedEventEmitter eventEmitter = shadowView.eventEmitter;
if (eventEmitter != nullptr) {
javaEventEmitter = EventEmitterWrapper::newObjectJavaArgs();
EventEmitterWrapper *cEventEmitter = cthis(javaEventEmitter);
cEventEmitter->eventEmitter = eventEmitter;
}
}
local_ref<JObject> props = getProps({}, shadowView);
auto component = getPlatformComponentName(shadowView);
preallocateView(
javaUIManager_,
surfaceId,
shadowView.tag,
component.get(),
props.get(),
(javaStateWrapper != nullptr ? javaStateWrapper.get() : nullptr),
(javaEventEmitter != nullptr ? javaEventEmitter.get() : nullptr),
isLayoutableShadowNode);
}
void FabricMountingManager::dispatchCommand(
ShadowView const &shadowView,
std::string const &commandName,
folly::dynamic const &args) {
static auto dispatchCommand =
jni::findClassStatic(UIManagerJavaDescriptor)
->getMethod<void(jint, jint, jstring, ReadableArray::javaobject)>(
"dispatchCommand");
local_ref<JString> command = make_jstring(commandName);
local_ref<ReadableArray::javaobject> argsArray =
castReadableArray(ReadableNativeArray::newObjectCxxArgs(args));
dispatchCommand(
javaUIManager_,
shadowView.surfaceId,
shadowView.tag,
command.get(),
argsArray.get());
}
void FabricMountingManager::sendAccessibilityEvent(
ShadowView const &shadowView,
std::string const &eventType) {
local_ref<JString> eventTypeStr = make_jstring(eventType);
static auto sendAccessibilityEventFromJS =
jni::findClassStatic(UIManagerJavaDescriptor)
->getMethod<void(jint, jint, jstring)>(
"sendAccessibilityEventFromJS");
sendAccessibilityEventFromJS(
javaUIManager_, shadowView.surfaceId, shadowView.tag, eventTypeStr.get());
}
void FabricMountingManager::setIsJSResponder(
ShadowView const &shadowView,
bool isJSResponder,
bool blockNativeResponder) {
static auto setJSResponder =
jni::findClassStatic(UIManagerJavaDescriptor)
->getMethod<void(jint, jint, jint, jboolean)>("setJSResponder");
static auto clearJSResponder = jni::findClassStatic(UIManagerJavaDescriptor)
->getMethod<void()>("clearJSResponder");
if (isJSResponder) {
setJSResponder(
javaUIManager_,
shadowView.surfaceId,
shadowView.tag,
// The closest non-flattened ancestor of the same value if the node is
// not flattened. For now, we don't support the case when the node can
// be flattened because the only component that uses this feature -
// ScrollView - cannot be flattened.
shadowView.tag,
(jboolean)blockNativeResponder);
} else {
clearJSResponder(javaUIManager_);
}
}
void FabricMountingManager::onAnimationStarted() {
static auto layoutAnimationsStartedJNI =
jni::findClassStatic(UIManagerJavaDescriptor)
->getMethod<void()>("onAnimationStarted");
layoutAnimationsStartedJNI(javaUIManager_);
}
void FabricMountingManager::onAllAnimationsComplete() {
static auto allAnimationsCompleteJNI =
jni::findClassStatic(UIManagerJavaDescriptor)
->getMethod<void()>("onAllAnimationsComplete");
allAnimationsCompleteJNI(javaUIManager_);
}
} // namespace react
} // namespace facebook
@@ -1,85 +0,0 @@
/*
* Copyright (c) Meta Platforms, Inc. and 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 "FabricMountItem.h"
#include <react/config/ReactNativeConfig.h>
#include <react/renderer/animations/LayoutAnimationDriver.h>
#include <react/renderer/mounting/MountingCoordinator.h>
#include <react/renderer/mounting/ShadowView.h>
#include <react/renderer/uimanager/LayoutAnimationStatusDelegate.h>
#include <react/utils/ContextContainer.h>
#include <fbjni/fbjni.h>
#include <mutex>
namespace facebook {
namespace react {
class FabricMountingManager final {
public:
constexpr static auto UIManagerJavaDescriptor =
"com/facebook/react/fabric/FabricUIManager";
constexpr static auto ReactFeatureFlagsJavaDescriptor =
"com/facebook/react/config/ReactFeatureFlags";
FabricMountingManager(
std::shared_ptr<const ReactNativeConfig> &config,
jni::global_ref<jobject> &javaUIManager);
void onSurfaceStart(SurfaceId surfaceId);
void onSurfaceStop(SurfaceId surfaceId);
void preallocateShadowView(SurfaceId surfaceId, ShadowView const &shadowView);
void executeMount(MountingCoordinator::Shared const &mountingCoordinator);
void dispatchCommand(
ShadowView const &shadowView,
std::string const &commandName,
folly::dynamic const &args);
void sendAccessibilityEvent(
const ShadowView &shadowView,
std::string const &eventType);
void setIsJSResponder(
ShadowView const &shadowView,
bool isJSResponder,
bool blockNativeResponder);
void onAnimationStarted();
void onAllAnimationsComplete();
private:
jni::global_ref<jobject> javaUIManager_;
std::recursive_mutex commitMutex_;
butter::map<SurfaceId, butter::set<Tag>> allocatedViewRegistry_{};
std::recursive_mutex allocatedViewsMutex_;
bool const enableEarlyEventEmitterUpdate_{false};
bool const disablePreallocateViews_{false};
bool const disableRevisionCheckForPreallocation_{false};
bool const useOverflowInset_{false};
bool const shouldRememberAllocatedViews_{false};
bool const useMapBufferForViewProps_{false};
jni::local_ref<jobject> getProps(
ShadowView const &oldShadowView,
ShadowView const &newShadowView);
};
} // namespace react
} // namespace facebook
@@ -1,30 +0,0 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#include "JBackgroundExecutor.h"
#include <fbjni/NativeRunnable.h>
#include <fbjni/fbjni.h>
namespace facebook {
namespace react {
using namespace facebook::jni;
BackgroundExecutor JBackgroundExecutor::create(const std::string &name) {
auto instance = make_global(newInstance(name));
return [instance = std::move(instance)](std::function<void()> &&runnable) {
static auto method =
javaClassStatic()->getMethod<void(JRunnable::javaobject)>(
"queueRunnable");
auto jrunnable = JNativeRunnable::newObjectCxxArgs(std::move(runnable));
method(instance, jrunnable.get());
};
}
} // namespace react
} // namespace facebook
@@ -1,27 +0,0 @@
/*
* Copyright (c) Meta Platforms, Inc. and 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 <fbjni/fbjni.h>
#include <react/renderer/uimanager/primitives.h>
namespace facebook {
namespace react {
using namespace facebook::jni;
class JBackgroundExecutor : public JavaClass<JBackgroundExecutor> {
public:
static auto constexpr kJavaDescriptor =
"Lcom/facebook/react/bridge/BackgroundExecutor;";
static BackgroundExecutor create(const std::string &name);
};
} // namespace react
} // namespace facebook
@@ -1,18 +0,0 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#include "JFabricUIManager.h"
namespace facebook::react {
Binding *JFabricUIManager::getBinding() {
static const auto bindingField =
javaClassStatic()->getField<Binding::javaobject>("mBinding");
return getFieldValue(bindingField)->cthis();
}
} // namespace facebook::react
@@ -1,25 +0,0 @@
/*
* Copyright (c) Meta Platforms, Inc. and 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 <fbjni/fbjni.h>
#include "Binding.h"
using namespace facebook::jni;
namespace facebook::react {
class JFabricUIManager : public JavaClass<JFabricUIManager> {
public:
static constexpr auto kJavaDescriptor =
"Lcom/facebook/react/fabric/FabricUIManager;";
Binding *getBinding();
};
} // namespace facebook::react
@@ -1,28 +0,0 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#include <fbjni/fbjni.h>
#include "Binding.h"
#include "ComponentFactory.h"
#include "CoreComponentsRegistry.h"
#include "EventBeatManager.h"
#include "EventEmitterWrapper.h"
#include "StateWrapperImpl.h"
#include "SurfaceHandlerBinding.h"
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *) {
return facebook::jni::initialize(vm, [] {
facebook::react::Binding::registerNatives();
facebook::react::EventBeatManager::registerNatives();
facebook::react::EventEmitterWrapper::registerNatives();
facebook::react::StateWrapperImpl::registerNatives();
facebook::react::ComponentFactory::registerNatives();
facebook::react::CoreComponentsRegistry::registerNatives();
facebook::react::SurfaceHandlerBinding::registerNatives();
});
}
@@ -1,41 +0,0 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#import "ReactNativeConfigHolder.h"
#include <fbjni/fbjni.h>
using namespace facebook::react;
bool ReactNativeConfigHolder::getBool(const std::string &param) const {
static const auto method = facebook::jni::findClassStatic(
"com/facebook/react/fabric/ReactNativeConfig")
->getMethod<jboolean(jstring)>("getBool");
return method(reactNativeConfig_, facebook::jni::make_jstring(param).get());
}
std::string ReactNativeConfigHolder::getString(const std::string &param) const {
static const auto method = facebook::jni::findClassStatic(
"com/facebook/react/fabric/ReactNativeConfig")
->getMethod<jstring(jstring)>("getString");
return method(reactNativeConfig_, facebook::jni::make_jstring(param).get())
->toString();
}
int64_t ReactNativeConfigHolder::getInt64(const std::string &param) const {
static const auto method = facebook::jni::findClassStatic(
"com/facebook/react/fabric/ReactNativeConfig")
->getMethod<jlong(jstring)>("getInt64");
return method(reactNativeConfig_, facebook::jni::make_jstring(param).get());
}
double ReactNativeConfigHolder::getDouble(const std::string &param) const {
static const auto method = facebook::jni::findClassStatic(
"com/facebook/react/fabric/ReactNativeConfig")
->getMethod<jdouble(jstring)>("getDouble");
return method(reactNativeConfig_, facebook::jni::make_jstring(param).get());
}
@@ -1,37 +0,0 @@
/*
* Copyright (c) Meta Platforms, Inc. and 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 <fbjni/fbjni.h>
#include <react/config/ReactNativeConfig.h>
#include <react/jni/ReadableNativeMap.h>
#include <memory>
namespace facebook {
namespace react {
/**
* Implementation of ReactNativeConfig that wraps a FabricMobileConfig Java
* object.
*/
class ReactNativeConfigHolder : public ReactNativeConfig {
public:
explicit ReactNativeConfigHolder(jni::alias_ref<jobject> reactNativeConfig)
: reactNativeConfig_(make_global(reactNativeConfig)){};
bool getBool(const std::string &param) const override;
std::string getString(const std::string &param) const override;
int64_t getInt64(const std::string &param) const override;
double getDouble(const std::string &param) const override;
private:
jni::global_ref<jobject> reactNativeConfig_;
};
} // namespace react
} // namespace facebook
@@ -1,62 +0,0 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#include "StateWrapperImpl.h"
#include <fbjni/fbjni.h>
#include <react/jni/ReadableNativeMap.h>
#include <react/renderer/mapbuffer/MapBuffer.h>
#include <react/renderer/mapbuffer/MapBufferBuilder.h>
using namespace facebook::jni;
namespace facebook {
namespace react {
/**
* Called from Java constructor through the JNI.
*/
jni::local_ref<StateWrapperImpl::jhybriddata> StateWrapperImpl::initHybrid(
jni::alias_ref<jclass>) {
return makeCxxInstance();
}
jni::local_ref<ReadableNativeMap::jhybridobject>
StateWrapperImpl::getStateDataImpl() {
folly::dynamic map = state_->getDynamic();
local_ref<ReadableNativeMap::jhybridobject> readableNativeMap =
ReadableNativeMap::newObjectCxxArgs(map);
return readableNativeMap;
}
jni::local_ref<JReadableMapBuffer::jhybridobject>
StateWrapperImpl::getStateMapBufferDataImpl() {
MapBuffer map = state_->getMapBuffer();
auto readableMapBuffer =
JReadableMapBuffer::createWithContents(std::move(map));
return readableMapBuffer;
}
void StateWrapperImpl::updateStateImpl(NativeMap *map) {
// Get folly::dynamic from map
auto dynamicMap = map->consume();
// Set state
state_->updateState(dynamicMap);
}
void StateWrapperImpl::registerNatives() {
registerHybrid({
makeNativeMethod("initHybrid", StateWrapperImpl::initHybrid),
makeNativeMethod("getStateDataImpl", StateWrapperImpl::getStateDataImpl),
makeNativeMethod("updateStateImpl", StateWrapperImpl::updateStateImpl),
makeNativeMethod(
"getStateMapBufferDataImpl",
StateWrapperImpl::getStateMapBufferDataImpl),
});
}
} // namespace react
} // namespace facebook
@@ -1,42 +0,0 @@
/*
* Copyright (c) Meta Platforms, Inc. and 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 <fbjni/fbjni.h>
#include <react/common/mapbuffer/JReadableMapBuffer.h>
#include <react/jni/ReadableNativeMap.h>
#include <react/renderer/core/State.h>
namespace facebook {
namespace react {
class Instance;
class StateWrapperImpl : public jni::HybridClass<StateWrapperImpl> {
public:
constexpr static const char *const kJavaDescriptor =
"Lcom/facebook/react/fabric/StateWrapperImpl;";
constexpr static auto StateWrapperImplJavaDescriptor =
"com/facebook/react/fabric/StateWrapperImpl";
static void registerNatives();
jni::local_ref<JReadableMapBuffer::jhybridobject> getStateMapBufferDataImpl();
jni::local_ref<ReadableNativeMap::jhybridobject> getStateDataImpl();
void updateStateImpl(NativeMap *map);
State::Shared state_;
private:
jni::alias_ref<StateWrapperImpl::jhybriddata> jhybridobject_;
static jni::local_ref<jhybriddata> initHybrid(jni::alias_ref<jclass>);
};
} // namespace react
} // namespace facebook
@@ -1,117 +0,0 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#include "SurfaceHandlerBinding.h"
#include <react/renderer/scheduler/Scheduler.h>
namespace facebook {
namespace react {
SurfaceHandlerBinding::SurfaceHandlerBinding(
SurfaceId surfaceId,
std::string const &moduleName)
: surfaceHandler_(moduleName, surfaceId) {}
void SurfaceHandlerBinding::setDisplayMode(jint mode) {
surfaceHandler_.setDisplayMode(static_cast<DisplayMode>(mode));
}
void SurfaceHandlerBinding::start() {
std::unique_lock<butter::shared_mutex> lock(lifecycleMutex_);
if (surfaceHandler_.getStatus() != SurfaceHandler::Status::Running) {
surfaceHandler_.start();
}
}
void SurfaceHandlerBinding::stop() {
std::unique_lock<butter::shared_mutex> lock(lifecycleMutex_);
if (surfaceHandler_.getStatus() == SurfaceHandler::Status::Running) {
surfaceHandler_.stop();
}
}
jint SurfaceHandlerBinding::getSurfaceId() {
return surfaceHandler_.getSurfaceId();
}
void SurfaceHandlerBinding::setSurfaceId(jint surfaceId) {
surfaceHandler_.setSurfaceId(surfaceId);
}
jboolean SurfaceHandlerBinding::isRunning() {
return surfaceHandler_.getStatus() == SurfaceHandler::Status::Running;
}
jni::local_ref<jstring> SurfaceHandlerBinding::getModuleName() {
return jni::make_jstring(surfaceHandler_.getModuleName());
}
jni::local_ref<SurfaceHandlerBinding::jhybriddata>
SurfaceHandlerBinding::initHybrid(
jni::alias_ref<jclass>,
jint surfaceId,
jni::alias_ref<jstring> moduleName) {
return makeCxxInstance(surfaceId, moduleName->toStdString());
}
void SurfaceHandlerBinding::setLayoutConstraints(
jfloat minWidth,
jfloat maxWidth,
jfloat minHeight,
jfloat maxHeight,
jfloat offsetX,
jfloat offsetY,
jboolean doLeftAndRightSwapInRTL,
jboolean isRTL,
jfloat pixelDensity) {
LayoutConstraints constraints = {};
constraints.minimumSize = {minWidth, minHeight};
constraints.maximumSize = {maxWidth, maxHeight};
constraints.layoutDirection =
isRTL ? LayoutDirection::RightToLeft : LayoutDirection::LeftToRight;
LayoutContext context = {};
context.swapLeftAndRightInRTL = doLeftAndRightSwapInRTL;
context.pointScaleFactor = pixelDensity;
context.viewportOffset = {offsetX, offsetY};
surfaceHandler_.constraintLayout(constraints, context);
}
void SurfaceHandlerBinding::setProps(NativeMap *props) {
surfaceHandler_.setProps(props->consume());
}
SurfaceHandler const &SurfaceHandlerBinding::getSurfaceHandler() {
return surfaceHandler_;
}
void SurfaceHandlerBinding::registerNatives() {
registerHybrid({
makeNativeMethod("initHybrid", SurfaceHandlerBinding::initHybrid),
makeNativeMethod(
"getSurfaceIdNative", SurfaceHandlerBinding::getSurfaceId),
makeNativeMethod(
"setSurfaceIdNative", SurfaceHandlerBinding::setSurfaceId),
makeNativeMethod("isRunningNative", SurfaceHandlerBinding::isRunning),
makeNativeMethod(
"getModuleNameNative", SurfaceHandlerBinding::getModuleName),
makeNativeMethod("startNative", SurfaceHandlerBinding::start),
makeNativeMethod("stopNative", SurfaceHandlerBinding::stop),
makeNativeMethod(
"setLayoutConstraintsNative",
SurfaceHandlerBinding::setLayoutConstraints),
makeNativeMethod("setPropsNative", SurfaceHandlerBinding::setProps),
makeNativeMethod(
"setDisplayModeNative", SurfaceHandlerBinding::setDisplayMode),
});
}
} // namespace react
} // namespace facebook
@@ -1,65 +0,0 @@
/*
* Copyright (c) Meta Platforms, Inc. and 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 <fbjni/fbjni.h>
#include <react/jni/ReadableNativeMap.h>
#include <react/renderer/scheduler/SurfaceHandler.h>
namespace facebook {
namespace react {
class SurfaceHandlerBinding : public jni::HybridClass<SurfaceHandlerBinding> {
public:
constexpr static const char *const kJavaDescriptor =
"Lcom/facebook/react/fabric/SurfaceHandlerBinding;";
static void registerNatives();
SurfaceHandlerBinding(SurfaceId surfaceId, std::string const &moduleName);
void start();
void stop();
void setDisplayMode(jint mode);
jint getSurfaceId();
void setSurfaceId(jint surfaceId);
jni::local_ref<jstring> getModuleName();
jboolean isRunning();
void setLayoutConstraints(
jfloat minWidth,
jfloat maxWidth,
jfloat minHeight,
jfloat maxHeight,
jfloat offsetX,
jfloat offsetY,
jboolean doLeftAndRightSwapInRTL,
jboolean isRTL,
jfloat pixelDensity);
void setProps(NativeMap *props);
SurfaceHandler const &getSurfaceHandler();
private:
mutable butter::shared_mutex lifecycleMutex_;
const SurfaceHandler surfaceHandler_;
jni::alias_ref<SurfaceHandlerBinding::jhybriddata> jhybridobject_;
static jni::local_ref<jhybriddata> initHybrid(
jni::alias_ref<jclass>,
jint surfaceId,
jni::alias_ref<jstring> moduleName);
};
} // namespace react
} // namespace facebook
@@ -1,555 +0,0 @@
/*
* Copyright (c) Meta Platforms, Inc. and 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 <react/renderer/components/view/ViewProps.h>
#include <react/renderer/components/view/conversions.h>
#include <react/renderer/graphics/conversions.h>
#include <react/renderer/mapbuffer/MapBuffer.h>
#include <react/renderer/mapbuffer/MapBufferBuilder.h>
#include <optional>
namespace facebook {
namespace react {
namespace {
// ViewProps values
constexpr MapBuffer::Key VP_ACCESSIBILITY_ACTIONS = 0;
constexpr MapBuffer::Key VP_ACCESSIBILITY_HINT = 1;
constexpr MapBuffer::Key VP_ACCESSIBILITY_LABEL = 2;
constexpr MapBuffer::Key VP_ACCESSIBILITY_LABELLED_BY = 3;
constexpr MapBuffer::Key VP_ACCESSIBILITY_LIVE_REGION = 4;
constexpr MapBuffer::Key VP_ACCESSIBILITY_ROLE = 5;
constexpr MapBuffer::Key VP_ACCESSIBILITY_STATE = 6;
constexpr MapBuffer::Key VP_ACCESSIBILITY_VALUE = 7;
constexpr MapBuffer::Key VP_ACCESSIBLE = 8;
constexpr MapBuffer::Key VP_BACKFACE_VISIBILITY = 9;
constexpr MapBuffer::Key VP_BG_COLOR = 10;
constexpr MapBuffer::Key VP_BORDER_COLOR = 11;
constexpr MapBuffer::Key VP_BORDER_RADII = 12;
constexpr MapBuffer::Key VP_BORDER_STYLE = 13;
constexpr MapBuffer::Key VP_COLLAPSABLE = 14;
constexpr MapBuffer::Key VP_ELEVATION = 15;
constexpr MapBuffer::Key VP_FOCUSABLE = 16;
constexpr MapBuffer::Key VP_HAS_TV_FOCUS = 17;
constexpr MapBuffer::Key VP_HIT_SLOP = 18;
constexpr MapBuffer::Key VP_IMPORTANT_FOR_ACCESSIBILITY = 19;
constexpr MapBuffer::Key VP_NATIVE_BACKGROUND = 20;
constexpr MapBuffer::Key VP_NATIVE_FOREGROUND = 21;
constexpr MapBuffer::Key VP_NATIVE_ID = 22;
constexpr MapBuffer::Key VP_OFFSCREEN_ALPHA_COMPOSITING = 23;
constexpr MapBuffer::Key VP_OPACITY = 24;
constexpr MapBuffer::Key VP_POINTER_EVENTS = 25;
constexpr MapBuffer::Key VP_POINTER_ENTER = 26;
constexpr MapBuffer::Key VP_POINTER_LEAVE = 27;
constexpr MapBuffer::Key VP_POINTER_MOVE = 28;
constexpr MapBuffer::Key VP_REMOVE_CLIPPED_SUBVIEW = 29;
constexpr MapBuffer::Key VP_RENDER_TO_HARDWARE_TEXTURE = 30;
constexpr MapBuffer::Key VP_SHADOW_COLOR = 31;
constexpr MapBuffer::Key VP_TEST_ID = 32;
constexpr MapBuffer::Key VP_TRANSFORM = 33;
constexpr MapBuffer::Key VP_ZINDEX = 34;
constexpr MapBuffer::Key VP_POINTER_ENTER_CAPTURE = 38;
constexpr MapBuffer::Key VP_POINTER_LEAVE_CAPTURE = 39;
constexpr MapBuffer::Key VP_POINTER_MOVE_CAPTURE = 40;
constexpr MapBuffer::Key VP_POINTER_OVER = 41;
constexpr MapBuffer::Key VP_POINTER_OVER_CAPTURE = 42;
constexpr MapBuffer::Key VP_POINTER_OUT = 43;
constexpr MapBuffer::Key VP_POINTER_OUT_CAPTURE = 44;
// Yoga values
constexpr MapBuffer::Key YG_BORDER_WIDTH = 100;
constexpr MapBuffer::Key YG_OVERFLOW = 101;
// AccessibilityAction values
constexpr MapBuffer::Key ACCESSIBILITY_ACTION_NAME = 0;
constexpr MapBuffer::Key ACCESSIBILITY_ACTION_LABEL = 1;
static MapBuffer convertAccessibilityActions(
std::vector<AccessibilityAction> const &actions) {
MapBufferBuilder builder(actions.size());
for (auto i = 0; i < actions.size(); i++) {
auto const &action = actions[i];
MapBufferBuilder actionsBuilder(2);
actionsBuilder.putString(ACCESSIBILITY_ACTION_NAME, action.name);
if (action.label.has_value()) {
actionsBuilder.putString(
ACCESSIBILITY_ACTION_LABEL, action.label.value());
}
builder.putMapBuffer(i, actionsBuilder.build());
}
return builder.build();
}
static MapBuffer convertAccessibilityLabelledBy(
AccessibilityLabelledBy const &labelledBy) {
MapBufferBuilder builder(labelledBy.value.size());
for (auto i = 0; i < labelledBy.value.size(); i++) {
builder.putString(i, labelledBy.value[i]);
}
return builder.build();
}
// AccessibilityState values
constexpr MapBuffer::Key ACCESSIBILITY_STATE_BUSY = 0;
constexpr MapBuffer::Key ACCESSIBILITY_STATE_DISABLED = 1;
constexpr MapBuffer::Key ACCESSIBILITY_STATE_EXPANDED = 2;
constexpr MapBuffer::Key ACCESSIBILITY_STATE_SELECTED = 3;
constexpr MapBuffer::Key ACCESSIBILITY_STATE_CHECKED = 4;
MapBuffer convertAccessibilityState(AccessibilityState const &state) {
MapBufferBuilder builder(5);
builder.putBool(ACCESSIBILITY_STATE_BUSY, state.busy);
builder.putBool(ACCESSIBILITY_STATE_DISABLED, state.disabled);
builder.putBool(ACCESSIBILITY_STATE_EXPANDED, state.expanded);
builder.putBool(ACCESSIBILITY_STATE_SELECTED, state.selected);
int checked;
switch (state.checked) {
case AccessibilityState::Unchecked:
checked = 0;
break;
case AccessibilityState::Checked:
checked = 1;
break;
case AccessibilityState::Mixed:
checked = 2;
break;
case AccessibilityState::None:
checked = 3;
break;
}
builder.putInt(ACCESSIBILITY_STATE_CHECKED, checked);
return builder.build();
}
inline void putOptionalColor(
MapBufferBuilder &builder,
MapBuffer::Key key,
std::optional<SharedColor> const &color) {
builder.putInt(key, color.has_value() ? toAndroidRepr(color.value()) : -1);
}
constexpr MapBuffer::Key EDGE_TOP = 0;
constexpr MapBuffer::Key EDGE_LEFT = 1;
constexpr MapBuffer::Key EDGE_RIGHT = 2;
constexpr MapBuffer::Key EDGE_BOTTOM = 3;
constexpr MapBuffer::Key EDGE_START = 4;
constexpr MapBuffer::Key EDGE_END = 5;
constexpr MapBuffer::Key EDGE_ALL = 6;
MapBuffer convertBorderColors(CascadedBorderColors const &colors) {
MapBufferBuilder builder(7);
putOptionalColor(builder, EDGE_TOP, colors.top);
putOptionalColor(builder, EDGE_RIGHT, colors.right);
putOptionalColor(builder, EDGE_BOTTOM, colors.bottom);
putOptionalColor(builder, EDGE_LEFT, colors.left);
putOptionalColor(builder, EDGE_START, colors.start);
putOptionalColor(builder, EDGE_END, colors.end);
putOptionalColor(builder, EDGE_ALL, colors.all);
return builder.build();
}
constexpr MapBuffer::Key CORNER_TOP_LEFT = 0;
constexpr MapBuffer::Key CORNER_TOP_RIGHT = 1;
constexpr MapBuffer::Key CORNER_BOTTOM_RIGHT = 2;
constexpr MapBuffer::Key CORNER_BOTTOM_LEFT = 3;
constexpr MapBuffer::Key CORNER_TOP_START = 4;
constexpr MapBuffer::Key CORNER_TOP_END = 5;
constexpr MapBuffer::Key CORNER_BOTTOM_END = 6;
constexpr MapBuffer::Key CORNER_BOTTOM_START = 7;
constexpr MapBuffer::Key CORNER_ALL = 8;
inline void putOptionalFloat(
MapBufferBuilder &builder,
MapBuffer::Key key,
std::optional<Float> const &value) {
builder.putDouble(key, value.value_or(NAN));
}
MapBuffer convertBorderRadii(CascadedBorderRadii const &radii) {
MapBufferBuilder builder(9);
putOptionalFloat(builder, CORNER_TOP_LEFT, radii.topLeft);
putOptionalFloat(builder, CORNER_TOP_RIGHT, radii.topRight);
putOptionalFloat(builder, CORNER_BOTTOM_RIGHT, radii.bottomRight);
putOptionalFloat(builder, CORNER_BOTTOM_LEFT, radii.bottomLeft);
putOptionalFloat(builder, CORNER_TOP_START, radii.topStart);
putOptionalFloat(builder, CORNER_TOP_END, radii.topEnd);
putOptionalFloat(builder, CORNER_BOTTOM_END, radii.bottomEnd);
putOptionalFloat(builder, CORNER_BOTTOM_START, radii.bottomStart);
putOptionalFloat(builder, CORNER_ALL, radii.all);
return builder.build();
}
MapBuffer convertBorderWidths(YGStyle::Edges const &border) {
MapBufferBuilder builder(7);
putOptionalFloat(
builder, EDGE_TOP, optionalFloatFromYogaValue(border[YGEdgeTop]));
putOptionalFloat(
builder, EDGE_RIGHT, optionalFloatFromYogaValue(border[YGEdgeRight]));
putOptionalFloat(
builder, EDGE_BOTTOM, optionalFloatFromYogaValue(border[YGEdgeBottom]));
putOptionalFloat(
builder, EDGE_LEFT, optionalFloatFromYogaValue(border[YGEdgeLeft]));
putOptionalFloat(
builder, EDGE_START, optionalFloatFromYogaValue(border[YGEdgeStart]));
putOptionalFloat(
builder, EDGE_END, optionalFloatFromYogaValue(border[YGEdgeEnd]));
putOptionalFloat(
builder, EDGE_ALL, optionalFloatFromYogaValue(border[YGEdgeAll]));
return builder.build();
}
MapBuffer convertEdgeInsets(EdgeInsets const &insets) {
MapBufferBuilder builder(4);
builder.putDouble(EDGE_TOP, insets.top);
builder.putDouble(EDGE_RIGHT, insets.right);
builder.putDouble(EDGE_BOTTOM, insets.bottom);
builder.putDouble(EDGE_LEFT, insets.left);
return builder.build();
}
#ifdef ANDROID
constexpr MapBuffer::Key NATIVE_DRAWABLE_KIND = 0;
constexpr MapBuffer::Key NATIVE_DRAWABLE_ATTRIBUTE = 1;
constexpr MapBuffer::Key NATIVE_DRAWABLE_COLOR = 2;
constexpr MapBuffer::Key NATIVE_DRAWABLE_BORDERLESS = 3;
constexpr MapBuffer::Key NATIVE_DRAWABLE_RIPPLE_RADIUS = 4;
MapBuffer convertNativeBackground(std::optional<NativeDrawable> const &value) {
if (!value.has_value()) {
return MapBufferBuilder::EMPTY();
}
auto const &drawable = value.value();
MapBufferBuilder builder(4);
switch (drawable.kind) {
case NativeDrawable::Kind::ThemeAttr:
builder.putInt(NATIVE_DRAWABLE_KIND, 0);
builder.putString(NATIVE_DRAWABLE_ATTRIBUTE, drawable.themeAttr);
break;
case NativeDrawable::Kind::Ripple:
builder.putInt(NATIVE_DRAWABLE_KIND, 1);
if (drawable.ripple.color.has_value()) {
builder.putInt(NATIVE_DRAWABLE_COLOR, drawable.ripple.color.value());
}
builder.putBool(NATIVE_DRAWABLE_BORDERLESS, drawable.ripple.borderless);
if (drawable.ripple.rippleRadius.has_value()) {
builder.putDouble(
NATIVE_DRAWABLE_RIPPLE_RADIUS,
drawable.ripple.rippleRadius.value());
}
break;
}
return builder.build();
}
#endif
MapBuffer convertTransform(Transform const &transform) {
MapBufferBuilder builder(16);
for (int32_t i = 0; i < transform.matrix.size(); i++) {
builder.putDouble(i, transform.matrix[i]);
}
return builder.build();
}
} // namespace
/**
* Diffs two sets of ViewProps into MapBuffer.
* TODO: Currently unsupported: nextFocusForward/Left/Up/Right/Down
*/
static inline MapBuffer viewPropsDiff(
ViewProps const &oldProps,
ViewProps const &newProps) {
MapBufferBuilder builder;
if (oldProps.accessibilityActions != newProps.accessibilityActions) {
builder.putMapBuffer(
VP_ACCESSIBILITY_ACTIONS,
convertAccessibilityActions(newProps.accessibilityActions));
}
if (oldProps.accessibilityHint != newProps.accessibilityHint) {
builder.putString(VP_ACCESSIBILITY_HINT, newProps.accessibilityHint);
}
if (oldProps.accessibilityLabel != newProps.accessibilityLabel) {
builder.putString(VP_ACCESSIBILITY_LABEL, newProps.accessibilityLabel);
}
if (oldProps.accessibilityLabelledBy != newProps.accessibilityLabelledBy) {
builder.putMapBuffer(
VP_ACCESSIBILITY_LABELLED_BY,
convertAccessibilityLabelledBy(newProps.accessibilityLabelledBy));
}
if (oldProps.accessibilityLiveRegion != newProps.accessibilityLiveRegion) {
int value;
switch (newProps.accessibilityLiveRegion) {
case AccessibilityLiveRegion::None:
value = 0;
break;
case AccessibilityLiveRegion::Polite:
value = 1;
break;
case AccessibilityLiveRegion::Assertive:
value = 2;
break;
}
builder.putInt(VP_ACCESSIBILITY_LIVE_REGION, value);
}
if (oldProps.accessibilityRole != newProps.accessibilityRole) {
builder.putString(VP_ACCESSIBILITY_ROLE, newProps.accessibilityRole);
}
if (oldProps.accessibilityState != newProps.accessibilityState) {
builder.putMapBuffer(
VP_ACCESSIBILITY_STATE,
convertAccessibilityState(newProps.accessibilityState));
}
if (oldProps.accessibilityValue != newProps.accessibilityValue) {
builder.putString(
VP_ACCESSIBILITY_VALUE, newProps.accessibilityValue.text.value_or(""));
}
if (oldProps.accessible != newProps.accessible) {
builder.putBool(VP_ACCESSIBLE, newProps.accessible);
}
if (oldProps.backfaceVisibility != newProps.backfaceVisibility) {
int value;
switch (newProps.backfaceVisibility) {
case BackfaceVisibility::Auto:
value = 0;
break;
case BackfaceVisibility::Visible:
value = 1;
break;
case BackfaceVisibility::Hidden:
value = 2;
break;
}
builder.putInt(VP_BACKFACE_VISIBILITY, value);
}
if (oldProps.backgroundColor != newProps.backgroundColor) {
builder.putInt(VP_BG_COLOR, toAndroidRepr(newProps.backgroundColor));
}
if (oldProps.borderColors != newProps.borderColors) {
builder.putMapBuffer(
VP_BORDER_COLOR, convertBorderColors(newProps.borderColors));
}
if (oldProps.borderRadii != newProps.borderRadii) {
builder.putMapBuffer(
VP_BORDER_RADII, convertBorderRadii(newProps.borderRadii));
}
if (oldProps.borderStyles != newProps.borderStyles) {
int value = -1;
if (newProps.borderStyles.all.has_value()) {
switch (newProps.borderStyles.all.value()) {
case BorderStyle::Solid:
value = 0;
break;
case BorderStyle::Dotted:
value = 1;
break;
case BorderStyle::Dashed:
value = 2;
break;
}
}
builder.putInt(VP_BORDER_STYLE, value);
}
if (oldProps.elevation != newProps.elevation) {
builder.putDouble(VP_ELEVATION, newProps.elevation);
}
#ifdef ANDROID
if (oldProps.focusable != newProps.focusable) {
builder.putBool(VP_FOCUSABLE, newProps.focusable);
}
if (oldProps.hasTVPreferredFocus != newProps.hasTVPreferredFocus) {
builder.putBool(VP_HAS_TV_FOCUS, newProps.hasTVPreferredFocus);
}
#endif
if (oldProps.hitSlop != newProps.hitSlop) {
builder.putMapBuffer(VP_HIT_SLOP, convertEdgeInsets(newProps.hitSlop));
}
if (oldProps.importantForAccessibility !=
newProps.importantForAccessibility) {
int value;
switch (newProps.importantForAccessibility) {
case ImportantForAccessibility::Auto:
value = 0;
break;
case ImportantForAccessibility::Yes:
value = 1;
break;
case ImportantForAccessibility::No:
value = 2;
break;
case ImportantForAccessibility::NoHideDescendants:
value = 3;
break;
}
builder.putInt(VP_IMPORTANT_FOR_ACCESSIBILITY, value);
}
#ifdef ANDROID
if (oldProps.nativeBackground != newProps.nativeBackground) {
builder.putMapBuffer(
VP_NATIVE_BACKGROUND,
convertNativeBackground(newProps.nativeBackground));
}
if (oldProps.nativeForeground != newProps.nativeForeground) {
builder.putMapBuffer(
VP_NATIVE_FOREGROUND,
convertNativeBackground(newProps.nativeForeground));
}
#endif
if (oldProps.nativeId != newProps.nativeId) {
builder.putString(VP_NATIVE_ID, newProps.nativeId);
}
#ifdef ANDROID
if (oldProps.needsOffscreenAlphaCompositing !=
newProps.needsOffscreenAlphaCompositing) {
builder.putBool(
VP_OFFSCREEN_ALPHA_COMPOSITING,
newProps.needsOffscreenAlphaCompositing);
}
#endif
if (oldProps.opacity != newProps.opacity) {
builder.putDouble(VP_OPACITY, newProps.opacity);
}
if (oldProps.pointerEvents != newProps.pointerEvents) {
int value;
switch (newProps.pointerEvents) {
case PointerEventsMode::Auto:
value = 0;
break;
case PointerEventsMode::None:
value = 1;
break;
case PointerEventsMode::BoxNone:
value = 2;
break;
case PointerEventsMode::BoxOnly:
value = 3;
break;
}
builder.putInt(VP_POINTER_EVENTS, value);
}
if (oldProps.events != newProps.events) {
builder.putBool(
VP_POINTER_ENTER, newProps.events[ViewEvents::Offset::PointerEnter]);
builder.putBool(
VP_POINTER_LEAVE, newProps.events[ViewEvents::Offset::PointerLeave]);
builder.putBool(
VP_POINTER_MOVE, newProps.events[ViewEvents::Offset::PointerMove]);
builder.putBool(
VP_POINTER_ENTER_CAPTURE,
newProps.events[ViewEvents::Offset::PointerEnterCapture]);
builder.putBool(
VP_POINTER_LEAVE_CAPTURE,
newProps.events[ViewEvents::Offset::PointerLeaveCapture]);
builder.putBool(
VP_POINTER_MOVE_CAPTURE,
newProps.events[ViewEvents::Offset::PointerMoveCapture]);
builder.putBool(
VP_POINTER_OVER, newProps.events[ViewEvents::Offset::PointerOver]);
builder.putBool(
VP_POINTER_OVER_CAPTURE,
newProps.events[ViewEvents::Offset::PointerOverCapture]);
builder.putBool(
VP_POINTER_OUT, newProps.events[ViewEvents::Offset::PointerOut]);
builder.putBool(
VP_POINTER_OUT_CAPTURE,
newProps.events[ViewEvents::Offset::PointerOutCapture]);
}
if (oldProps.removeClippedSubviews != newProps.removeClippedSubviews) {
builder.putBool(VP_REMOVE_CLIPPED_SUBVIEW, newProps.removeClippedSubviews);
}
#ifdef ANDROID
if (oldProps.renderToHardwareTextureAndroid !=
newProps.renderToHardwareTextureAndroid) {
builder.putBool(
VP_RENDER_TO_HARDWARE_TEXTURE, newProps.renderToHardwareTextureAndroid);
}
#endif
if (oldProps.shadowColor != newProps.shadowColor) {
builder.putInt(VP_SHADOW_COLOR, toAndroidRepr(newProps.shadowColor));
}
if (oldProps.testId != newProps.testId) {
builder.putString(VP_TEST_ID, newProps.testId);
}
// TODO: seems like transform covers rotation/translate/scale/skew?
if (oldProps.transform != newProps.transform) {
builder.putMapBuffer(VP_TRANSFORM, convertTransform(newProps.transform));
}
if (oldProps.zIndex != newProps.zIndex) {
builder.putInt(VP_ZINDEX, newProps.zIndex.value_or(0));
}
if (oldProps.yogaStyle != newProps.yogaStyle) {
auto const &oldStyle = oldProps.yogaStyle;
auto const &newStyle = newProps.yogaStyle;
if (!(oldStyle.border() == newStyle.border())) {
builder.putMapBuffer(
YG_BORDER_WIDTH, convertBorderWidths(newStyle.border()));
}
if (oldStyle.overflow() != newStyle.overflow()) {
int value;
switch (newStyle.overflow()) {
case YGOverflowVisible:
value = 0;
break;
case YGOverflowHidden:
value = 1;
break;
case YGOverflowScroll:
value = 2;
break;
}
builder.putInt(YG_OVERFLOW, value);
}
}
return builder.build();
}
} // namespace react
} // namespace facebook