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,21 @@
# 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_idlecallbacks_SRC CONFIGURE_DEPENDS *.cpp)
add_library(react_nativemodule_idlecallbacks OBJECT ${react_nativemodule_idlecallbacks_SRC})
target_include_directories(react_nativemodule_idlecallbacks PUBLIC ${REACT_COMMON_DIR})
target_link_libraries(react_nativemodule_idlecallbacks
react_codegen_rncore
react_cxxreact
react_renderer_runtimescheduler
)
target_compile_reactnative_options(react_nativemodule_idlecallbacks PRIVATE)
target_compile_options(react_nativemodule_idlecallbacks PRIVATE -Wpedantic)

View File

@@ -0,0 +1,161 @@
/*
* 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 "NativeIdleCallbacks.h"
#include <react/renderer/runtimescheduler/RuntimeScheduler.h>
#include <react/renderer/runtimescheduler/RuntimeSchedulerBinding.h>
#include <react/renderer/runtimescheduler/Task.h>
#include <react/timing/primitives.h>
#include <utility>
#ifdef RN_DISABLE_OSS_PLUGIN_HEADER
#include "Plugins.h"
#endif
std::shared_ptr<facebook::react::TurboModule> NativeIdleCallbacksModuleProvider(
std::shared_ptr<facebook::react::CallInvoker> jsInvoker) {
return std::make_shared<facebook::react::NativeIdleCallbacks>(
std::move(jsInvoker));
}
namespace facebook::react {
namespace {
class IdleTaskRef : public jsi::NativeState {
public:
explicit IdleTaskRef(std::shared_ptr<Task> task) : task(std::move(task)) {}
std::shared_ptr<Task> task;
};
jsi::Function makeTimeRemainingFunction(
jsi::Runtime& runtime,
std::shared_ptr<RuntimeScheduler> runtimeScheduler,
HighResTimeStamp deadline) {
return jsi::Function::createFromHostFunction(
runtime,
jsi::PropNameID::forAscii(runtime, "timeRemaining"),
0,
[runtimeScheduler, deadline, expired = false](
jsi::Runtime& runtime,
const jsi::Value& /* unused */,
const jsi::Value* /* unused */,
size_t /* unused */) mutable {
double remainingTime = 0;
// No need to access the runtime scheduler if this idle callback expired
// already.
if (!expired) {
if (runtimeScheduler->getShouldYield()) {
expired = true;
} else {
auto now = runtimeScheduler->now();
auto diff = deadline - now;
remainingTime = std::max(diff.toDOMHighResTimeStamp(), 0.0);
if (remainingTime == 0) {
expired = true;
}
}
}
return jsi::Value(runtime, remainingTime);
});
}
} // namespace
NativeIdleCallbacks::NativeIdleCallbacks(std::shared_ptr<CallInvoker> jsInvoker)
: NativeIdleCallbacksCxxSpec(std::move(jsInvoker)) {}
CallbackHandle NativeIdleCallbacks::requestIdleCallback(
jsi::Runtime& runtime,
SyncCallback<void(jsi::Object)>&& userCallback,
std::optional<NativeRequestIdleCallbackOptions> options) {
auto binding = RuntimeSchedulerBinding::getBinding(runtime);
auto runtimeScheduler = binding->getRuntimeScheduler();
// handle timeout parameter
std::optional<HighResDuration> timeout;
std::optional<HighResTimeStamp> expirationTime;
if (options.has_value() && options.value().timeout.has_value()) {
HighResDuration userTimeout = options.value().timeout.value();
if (userTimeout > HighResDuration::zero()) {
expirationTime = runtimeScheduler->now() + userTimeout;
}
}
auto userCallbackShared = std::make_shared<SyncCallback<void(jsi::Object)>>(
std::move(userCallback));
auto wrappedCallback = [runtimeScheduler, expirationTime, userCallbackShared](
jsi::Runtime& runtime) -> void {
// This implementation gives each idle callback a 50ms deadline, instead of
// being shared by all idle callbacks. This is ok because we don't really
// have idle periods, and if a higher priority task comes in while we're
// executing an idle callback, we don't execute any more idle callbacks and
// we interrupt the current one. The general outcome should be the same.
auto executionStartTime = runtimeScheduler->now();
auto deadline = executionStartTime + HighResDuration::fromMilliseconds(50);
auto didTimeout = expirationTime.has_value()
? executionStartTime > expirationTime
: false;
jsi::Object idleDeadline{runtime};
idleDeadline.setProperty(runtime, "didTimeout", didTimeout);
idleDeadline.setProperty(
runtime,
"timeRemaining",
makeTimeRemainingFunction(runtime, runtimeScheduler, deadline));
userCallbackShared->call(std::move(idleDeadline));
};
std::shared_ptr<Task> task;
if (timeout.has_value()) {
task = runtimeScheduler->scheduleIdleTask(
std::move(wrappedCallback), timeout.value());
} else {
task = runtimeScheduler->scheduleIdleTask(std::move(wrappedCallback));
}
if (task == nullptr) {
throw jsi::JSError(
runtime,
"requestIdleCallback is not supported in legacy runtime scheduler");
}
jsi::Object taskHandle{runtime};
auto taskNativeState = std::make_shared<IdleTaskRef>(task);
taskHandle.setNativeState(runtime, std::move(taskNativeState));
return taskHandle;
}
void NativeIdleCallbacks::cancelIdleCallback(
jsi::Runtime& runtime,
jsi::Object handle) {
auto binding = RuntimeSchedulerBinding::getBinding(runtime);
auto runtimeScheduler = binding->getRuntimeScheduler();
if (!handle.hasNativeState(runtime)) {
return;
}
auto taskHandle =
std::dynamic_pointer_cast<IdleTaskRef>(handle.getNativeState(runtime));
if (!taskHandle) {
return;
}
runtimeScheduler->cancelTask(*taskHandle->task);
}
} // namespace facebook::react

View File

@@ -0,0 +1,37 @@
/*
* 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
#if __has_include("FBReactNativeSpecJSI.h") // CocoaPod headers on Apple
#include "FBReactNativeSpecJSI.h"
#else
#include <FBReactNativeSpec/FBReactNativeSpecJSI.h>
#endif
namespace facebook::react {
using CallbackHandle = jsi::Object;
using NativeRequestIdleCallbackOptions = NativeIdleCallbacksRequestIdleCallbackOptions<std::optional<HighResDuration>>;
template <>
struct Bridging<NativeRequestIdleCallbackOptions>
: NativeIdleCallbacksRequestIdleCallbackOptionsBridging<NativeRequestIdleCallbackOptions> {};
class NativeIdleCallbacks : public NativeIdleCallbacksCxxSpec<NativeIdleCallbacks> {
public:
NativeIdleCallbacks(std::shared_ptr<CallInvoker> jsInvoker);
CallbackHandle requestIdleCallback(
jsi::Runtime &runtime,
SyncCallback<void(jsi::Object)> &&callback,
std::optional<NativeRequestIdleCallbackOptions> options);
void cancelIdleCallback(jsi::Runtime &runtime, jsi::Object handle);
};
} // namespace facebook::react

View File

@@ -0,0 +1,55 @@
# 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.
require "json"
package = JSON.parse(File.read(File.join(__dir__, "..", "..", "..", "..", "package.json")))
version = package['version']
source = { :git => 'https://github.com/facebook/react-native.git' }
if version == '1000.0.0'
# This is an unpublished version, use the latest commit hash of the react-native repo, which were presumably in.
source[:commit] = `git rev-parse HEAD`.strip if system("git rev-parse --git-dir > /dev/null 2>&1")
else
source[:tag] = "v#{version}"
end
header_search_paths = []
if ENV['USE_FRAMEWORKS']
header_search_paths << "\"$(PODS_TARGET_SRCROOT)/../../..\"" # this is needed to allow the module access its own files
end
Pod::Spec.new do |s|
s.name = "React-idlecallbacksnativemodule"
s.version = version
s.summary = "React Native idle callbacks native module"
s.homepage = "https://reactnative.dev/"
s.license = package["license"]
s.author = "Meta Platforms, Inc. and its affiliates"
s.platforms = min_supported_versions
s.source = source
s.source_files = podspec_sources("*.{cpp,h}", "*.h")
s.header_dir = "react/nativemodule/idlecallbacks"
s.pod_target_xcconfig = { "CLANG_CXX_LANGUAGE_STANDARD" => rct_cxx_language_standard(),
"HEADER_SEARCH_PATHS" => header_search_paths.join(' '),
"OTHER_CFLAGS" => "$(inherited)",
"DEFINES_MODULE" => "YES" }
resolve_use_frameworks(s, header_mappings_dir: "../..", module_name: "idlecallbacksnativemodule")
s.dependency "React-jsi"
s.dependency "React-jsiexecutor"
depend_on_js_engine(s)
add_rn_third_party_dependencies(s)
add_rncore_dependency(s)
s.dependency "ReactCommon/turbomodule/core"
s.dependency "React-runtimescheduler"
add_dependency(s, "React-RCTFBReactNativeSpec")
add_dependency(s, "React-runtimeexecutor", :additional_framework_paths => ["platform/ios"])
end