mirror of
https://github.com/facebook/react-native.git
synced 2025-11-01 09:14:26 +00:00
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:
committed by
Facebook GitHub Bot
parent
1bd27609b3
commit
4706d13ec8
@@ -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 ¶m) 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 ¶m) 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 ¶m) 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 ¶m) 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 ¶m) const override;
|
||||
std::string getString(const std::string ¶m) const override;
|
||||
int64_t getInt64(const std::string ¶m) const override;
|
||||
double getDouble(const std::string ¶m) 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
|
||||
Reference in New Issue
Block a user