first commit

This commit is contained in:
2026-03-10 16:18:05 +00:00
commit 11f9c069b5
31635 changed files with 3187747 additions and 0 deletions

View File

@@ -0,0 +1,27 @@
# 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)
set(CMAKE_VERBOSE_MAKEFILE on)
include(${REACT_COMMON_DIR}/cmake-utils/react-native-flags.cmake)
file(GLOB react_nativemodule_mutationobserver_SRC CONFIGURE_DEPENDS *.cpp)
add_library(react_nativemodule_mutationobserver OBJECT ${react_nativemodule_mutationobserver_SRC})
target_include_directories(react_nativemodule_mutationobserver PUBLIC ${REACT_COMMON_DIR})
target_link_libraries(react_nativemodule_mutationobserver
react_codegen_rncore
react_renderer_bridging
react_renderer_core
react_renderer_uimanager
react_featureflags
react_renderer_observers_mutation
react_cxxreact
rrc_view
)
target_compile_reactnative_options(react_nativemodule_mutationobserver PRIVATE)
target_compile_options(react_nativemodule_mutationobserver PRIVATE -Wpedantic)

View File

@@ -0,0 +1,159 @@
/*
* 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 "NativeMutationObserver.h"
#include <cxxreact/TraceSection.h>
#include <react/featureflags/ReactNativeFeatureFlags.h>
#include <react/renderer/core/ShadowNode.h>
#include <react/renderer/uimanager/UIManagerBinding.h>
#include <react/renderer/uimanager/primitives.h>
#ifdef RN_DISABLE_OSS_PLUGIN_HEADER
#include "Plugins.h"
#endif
std::shared_ptr<facebook::react::TurboModule>
NativeMutationObserverModuleProvider(
std::shared_ptr<facebook::react::CallInvoker> jsInvoker) {
return std::make_shared<facebook::react::NativeMutationObserver>(
std::move(jsInvoker));
}
namespace facebook::react {
static UIManager& getUIManagerFromRuntime(jsi::Runtime& runtime) {
return UIManagerBinding::getBinding(runtime)->getUIManager();
}
NativeMutationObserver::NativeMutationObserver(
std::shared_ptr<CallInvoker> jsInvoker)
: NativeMutationObserverCxxSpec(std::move(jsInvoker)) {}
void NativeMutationObserver::observe(
jsi::Runtime& runtime,
const NativeMutationObserverObserveOptions& options) {
auto mutationObserverId = options.mutationObserverId;
auto subtree = options.subtree;
auto shadowNode = options.targetShadowNode;
auto& uiManager = getUIManagerFromRuntime(runtime);
mutationObserverManager_.observe(
mutationObserverId, shadowNode, subtree, uiManager);
}
void NativeMutationObserver::unobserveAll(
jsi::Runtime& /*runtime*/,
MutationObserverId mutationObserverId) {
mutationObserverManager_.unobserveAll(mutationObserverId);
}
void NativeMutationObserver::connect(
jsi::Runtime& runtime,
jsi::Function notifyMutationObservers,
SyncCallback<jsi::Value(jsi::Value)> getPublicInstanceFromInstanceHandle) {
auto& uiManager = getUIManagerFromRuntime(runtime);
runtime_ = &runtime;
notifyMutationObservers_.emplace(std::move(notifyMutationObservers));
getPublicInstanceFromInstanceHandle_.emplace(
std::move(getPublicInstanceFromInstanceHandle));
auto onMutationsCallback = [&](std::vector<MutationRecord>& records) {
return onMutations(records);
};
mutationObserverManager_.connect(uiManager, std::move(onMutationsCallback));
}
void NativeMutationObserver::disconnect(jsi::Runtime& runtime) {
auto& uiManager = getUIManagerFromRuntime(runtime);
mutationObserverManager_.disconnect(uiManager);
runtime_ = nullptr;
notifyMutationObservers_.reset();
getPublicInstanceFromInstanceHandle_.reset();
}
std::vector<NativeMutationRecord> NativeMutationObserver::takeRecords(
jsi::Runtime& /*runtime*/) {
notifiedMutationObservers_ = false;
std::vector<NativeMutationRecord> records;
pendingRecords_.swap(records);
return records;
}
jsi::Value NativeMutationObserver::getPublicInstanceFromShadowNode(
const ShadowNode& shadowNode) const {
auto instanceHandle = shadowNode.getInstanceHandle(*runtime_);
if (!instanceHandle.isObject()) {
return jsi::Value::null();
}
return getPublicInstanceFromInstanceHandle_.value().call(
std::move(instanceHandle));
}
std::vector<jsi::Value>
NativeMutationObserver::getPublicInstancesFromShadowNodes(
const std::vector<std::shared_ptr<const ShadowNode>>& shadowNodes) const {
std::vector<jsi::Value> publicInstances;
publicInstances.reserve(shadowNodes.size());
for (const auto& shadowNode : shadowNodes) {
publicInstances.push_back(getPublicInstanceFromShadowNode(*shadowNode));
}
return publicInstances;
}
void NativeMutationObserver::onMutations(std::vector<MutationRecord>& records) {
TraceSection s("NativeMutationObserver::onMutations");
for (const auto& record : records) {
pendingRecords_.emplace_back(
NativeMutationRecord{
record.mutationObserverId,
// FIXME(T157129303) Instead of assuming we can call into JS from
// here, we should use an API that explicitly indicates it.
getPublicInstanceFromShadowNode(*record.targetShadowNode),
getPublicInstancesFromShadowNodes(record.addedShadowNodes),
getPublicInstancesFromShadowNodes(record.removedShadowNodes)});
}
notifyMutationObserversIfNecessary();
}
/**
* This method allows us to avoid scheduling multiple calls to notify observers
* in the JS thread. We schedule one and skip subsequent ones (we just append
* the records to the pending list and wait for the scheduled task to consume
* all of them).
*/
void NativeMutationObserver::notifyMutationObserversIfNecessary() {
bool dispatchNotification = false;
if (!pendingRecords_.empty() && !notifiedMutationObservers_) {
notifiedMutationObservers_ = true;
dispatchNotification = true;
}
if (dispatchNotification) {
TraceSection s("NativeMutationObserver::notifyObservers");
if (ReactNativeFeatureFlags::enableBridgelessArchitecture()) {
runtime_->queueMicrotask(notifyMutationObservers_.value());
} else {
jsInvoker_->invokeAsync([&](jsi::Runtime& runtime) {
// It's possible that the last observer was disconnected before we could
// dispatch this notification.
if (notifyMutationObservers_) {
notifyMutationObservers_.value().call(runtime);
}
});
}
}
}
} // namespace facebook::react

View File

@@ -0,0 +1,83 @@
/*
* 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 <FBReactNativeSpec/FBReactNativeSpecJSI.h>
#include <react/renderer/bridging/bridging.h>
#include <react/renderer/observers/mutation/MutationObserverManager.h>
#include <react/renderer/uimanager/UIManager.h>
#include <vector>
namespace facebook::react {
using NativeMutationObserverObserveOptions = NativeMutationObserverNativeMutationObserverObserveOptions<
// mutationObserverId
MutationObserverId,
// targetShadowNode
std::shared_ptr<const ShadowNode>,
// subtree
bool>;
template <>
struct Bridging<NativeMutationObserverObserveOptions>
: NativeMutationObserverNativeMutationObserverObserveOptionsBridging<NativeMutationObserverObserveOptions> {};
using NativeMutationRecord = NativeMutationObserverNativeMutationRecord<
// mutationObserverId
MutationObserverId,
// target
jsi::Value,
// addedNodes
std::vector<jsi::Value>,
// removedNodes
std::vector<jsi::Value>>;
template <>
struct Bridging<NativeMutationRecord> : NativeMutationObserverNativeMutationRecordBridging<NativeMutationRecord> {};
class NativeMutationObserver : public NativeMutationObserverCxxSpec<NativeMutationObserver> {
public:
NativeMutationObserver(std::shared_ptr<CallInvoker> jsInvoker);
void observe(jsi::Runtime &runtime, const NativeMutationObserverObserveOptions &options);
void unobserveAll(jsi::Runtime &runtime, MutationObserverId mutationObserverId);
void connect(
jsi::Runtime &runtime,
jsi::Function notifyMutationObservers,
SyncCallback<jsi::Value(jsi::Value)> getPublicInstanceFromInstanceHandle);
void disconnect(jsi::Runtime &runtime);
std::vector<NativeMutationRecord> takeRecords(jsi::Runtime &runtime);
private:
MutationObserverManager mutationObserverManager_{};
std::vector<NativeMutationRecord> pendingRecords_;
// We need to keep a reference to the JS runtime so we can schedule the
// notifications as microtasks when mutations occur. This is safe because
// mutations will only happen when executing JavaScript and because this
// native module will never survive the runtime.
jsi::Runtime *runtime_{};
bool notifiedMutationObservers_{};
std::optional<jsi::Function> notifyMutationObservers_;
std::optional<SyncCallback<jsi::Value(jsi::Value)>> getPublicInstanceFromInstanceHandle_;
void onMutations(std::vector<MutationRecord> &records);
void notifyMutationObserversIfNecessary();
jsi::Value getPublicInstanceFromShadowNode(const ShadowNode &shadowNode) const;
std::vector<jsi::Value> getPublicInstancesFromShadowNodes(
const std::vector<std::shared_ptr<const ShadowNode>> &shadowNodes) const;
};
} // namespace facebook::react