mirror of
https://github.com/facebook/react-native.git
synced 2025-11-01 09:14:26 +00:00
Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1aa3d3f864 |
@@ -14,23 +14,23 @@ runs:
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: hermes-workspace
|
||||
path: 'C:\tmp\hermes'
|
||||
path: 'D:\tmp\hermes'
|
||||
- name: Set up workspace
|
||||
shell: powershell
|
||||
run: |
|
||||
mkdir -p C:\tmp\hermes\osx-bin
|
||||
mkdir -p D:\tmp\hermes\osx-bin
|
||||
mkdir -p .\packages\react-native\sdks\hermes
|
||||
cp -r -Force C:\tmp\hermes\hermes\* .\packages\react-native\sdks\hermes\.
|
||||
cp -r -Force D:\tmp\hermes\hermes\* .\packages\react-native\sdks\hermes\.
|
||||
cp -r -Force .\packages\react-native\sdks\hermes-engine\utils\* .\packages\react-native\sdks\hermes\.
|
||||
- name: Windows cache
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
key: v3-hermes-${{ github.job }}-windows-${{ inputs.hermes-version }}-${{ inputs.react-native-version }}
|
||||
path: |
|
||||
C:\tmp\hermes\win64-bin\
|
||||
C:\tmp\hermes\hermes\icu\
|
||||
C:\tmp\hermes\hermes\deps\
|
||||
C:\tmp\hermes\hermes\build_release\
|
||||
D:\tmp\hermes\win64-bin\
|
||||
D:\tmp\hermes\hermes\icu\
|
||||
D:\tmp\hermes\hermes\deps\
|
||||
D:\tmp\hermes\hermes\build_release\
|
||||
- name: setup-msbuild
|
||||
uses: microsoft/setup-msbuild@v1.3.2
|
||||
- name: Set up workspace
|
||||
@@ -83,4 +83,4 @@ runs:
|
||||
uses: actions/upload-artifact@v4.3.4
|
||||
with:
|
||||
name: hermes-win64-bin
|
||||
path: C:\tmp\hermes\win64-bin\
|
||||
path: D:\tmp\hermes\win64-bin\
|
||||
|
||||
@@ -128,9 +128,9 @@ jobs:
|
||||
runs-on: windows-2025
|
||||
needs: prepare_hermes_workspace
|
||||
env:
|
||||
HERMES_WS_DIR: 'C:\tmp\hermes'
|
||||
HERMES_TARBALL_ARTIFACTS_DIR: 'C:\tmp\hermes\hermes-runtime-darwin'
|
||||
HERMES_OSXBIN_ARTIFACTS_DIR: 'C:\tmp\hermes\osx-bin'
|
||||
HERMES_WS_DIR: 'D:\tmp\hermes'
|
||||
HERMES_TARBALL_ARTIFACTS_DIR: 'D:\tmp\hermes\hermes-runtime-darwin'
|
||||
HERMES_OSXBIN_ARTIFACTS_DIR: 'D:\tmp\hermes\osx-bin'
|
||||
ICU_URL: "https://github.com/unicode-org/icu/releases/download/release-64-2/icu4c-64_2-Win64-MSVC2017.zip"
|
||||
MSBUILD_DIR: 'C:\Program Files (x86)\Microsoft Visual Studio\2019\BuildTools\MSBuild\Current\Bin'
|
||||
CMAKE_DIR: 'C:\Program Files\CMake\bin'
|
||||
|
||||
@@ -125,9 +125,9 @@ jobs:
|
||||
runs-on: windows-2025
|
||||
needs: prepare_hermes_workspace
|
||||
env:
|
||||
HERMES_WS_DIR: 'C:\tmp\hermes'
|
||||
HERMES_TARBALL_ARTIFACTS_DIR: 'C:\tmp\hermes\hermes-runtime-darwin'
|
||||
HERMES_OSXBIN_ARTIFACTS_DIR: 'C:\tmp\hermes\osx-bin'
|
||||
HERMES_WS_DIR: 'D:\tmp\hermes'
|
||||
HERMES_TARBALL_ARTIFACTS_DIR: 'D:\tmp\hermes\hermes-runtime-darwin'
|
||||
HERMES_OSXBIN_ARTIFACTS_DIR: 'D:\tmp\hermes\osx-bin'
|
||||
ICU_URL: "https://github.com/unicode-org/icu/releases/download/release-64-2/icu4c-64_2-Win64-MSVC2017.zip"
|
||||
MSBUILD_DIR: 'C:\Program Files (x86)\Microsoft Visual Studio\2019\BuildTools\MSBuild\Current\Bin'
|
||||
CMAKE_DIR: 'C:\Program Files\CMake\bin'
|
||||
|
||||
@@ -382,9 +382,9 @@ jobs:
|
||||
runs-on: windows-2025
|
||||
needs: prepare_hermes_workspace
|
||||
env:
|
||||
HERMES_WS_DIR: 'C:\tmp\hermes'
|
||||
HERMES_TARBALL_ARTIFACTS_DIR: 'C:\tmp\hermes\hermes-runtime-darwin'
|
||||
HERMES_OSXBIN_ARTIFACTS_DIR: 'C:\tmp\hermes\osx-bin'
|
||||
HERMES_WS_DIR: 'D:\tmp\hermes'
|
||||
HERMES_TARBALL_ARTIFACTS_DIR: 'D:\tmp\hermes\hermes-runtime-darwin'
|
||||
HERMES_OSXBIN_ARTIFACTS_DIR: 'D:\tmp\hermes\osx-bin'
|
||||
ICU_URL: "https://github.com/unicode-org/icu/releases/download/release-64-2/icu4c-64_2-Win64-MSVC2017.zip"
|
||||
MSBUILD_DIR: 'C:\Program Files (x86)\Microsoft Visual Studio\2019\BuildTools\MSBuild\Current\Bin'
|
||||
CMAKE_DIR: 'C:\Program Files\CMake\bin'
|
||||
@@ -583,7 +583,7 @@ jobs:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
node-version: ["24", "22", "20"]
|
||||
node-version: ["24", "22"]
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
],
|
||||
"bugs": "https://github.com/facebook/react-native/issues",
|
||||
"engines": {
|
||||
"node": ">= 20.19.4"
|
||||
"node": ">= 22.14.0"
|
||||
},
|
||||
"files": [
|
||||
"path-support.js",
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
],
|
||||
"bugs": "https://github.com/facebook/react-native/issues",
|
||||
"engines": {
|
||||
"node": ">= 20.19.4"
|
||||
"node": ">= 22.14.0"
|
||||
},
|
||||
"files": [
|
||||
"index.js"
|
||||
|
||||
@@ -43,6 +43,6 @@
|
||||
}
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 20.19.4"
|
||||
"node": ">= 22.14.0"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
],
|
||||
"bugs": "https://github.com/facebook/react-native/issues",
|
||||
"engines": {
|
||||
"node": ">= 20.19.4"
|
||||
"node": ">= 22.14.0"
|
||||
},
|
||||
"files": [
|
||||
"dist"
|
||||
|
||||
@@ -20,6 +20,6 @@
|
||||
"BUILD_INFO"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">= 20.19.4"
|
||||
"node": ">= 22.14.0"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
},
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 20.19.4",
|
||||
"node": ">= 22.14.0",
|
||||
"electron": ">=36.3.0"
|
||||
},
|
||||
"dependencies": {
|
||||
|
||||
@@ -10,25 +10,9 @@
|
||||
|
||||
// $FlowFixMe[unclear-type] We have no Flow types for the Electron API.
|
||||
const {app} = require('electron') as any;
|
||||
const util = require('util');
|
||||
|
||||
// Handle global command line arguments which don't require a window
|
||||
// or the single instance lock to be held.
|
||||
const {
|
||||
values: {version = false},
|
||||
} = util.parseArgs({
|
||||
options: {version: {type: 'boolean'}},
|
||||
args: process.argv.slice(app.isPackaged ? 1 : 2),
|
||||
strict: false,
|
||||
});
|
||||
if (version) {
|
||||
console.log(`${app.getName()} v${app.getVersion()}`);
|
||||
// Not app.quit() - we want to exit immediately without initialising the graphical subsystem.
|
||||
app.exit(0);
|
||||
}
|
||||
|
||||
const gotTheLock = app.requestSingleInstanceLock({
|
||||
argv: process.argv.slice(app.isPackaged ? 1 : 2),
|
||||
argv: process.argv.slice(2),
|
||||
});
|
||||
|
||||
if (!gotTheLock) {
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
"ws": "^6.2.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 20.19.4"
|
||||
"node": ">= 22.14.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"selfsigned": "^2.4.1",
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
],
|
||||
"bugs": "https://github.com/facebook/react-native/issues",
|
||||
"engines": {
|
||||
"node": ">= 20.19.4"
|
||||
"node": ">= 22.14.0"
|
||||
},
|
||||
"main": "index.js",
|
||||
"dependencies": {
|
||||
|
||||
@@ -22,6 +22,6 @@
|
||||
"hermes-eslint": "0.29.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 20.19.4"
|
||||
"node": ">= 22.14.0"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,6 +36,6 @@
|
||||
"hermes-eslint": "0.29.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 20.19.4"
|
||||
"node": ">= 22.14.0"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
],
|
||||
"bugs": "https://github.com/facebook/react-native/issues",
|
||||
"engines": {
|
||||
"node": ">= 20.19.4"
|
||||
"node": ">= 22.14.0"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "./gradlew build",
|
||||
|
||||
-2
@@ -18,7 +18,6 @@ import com.facebook.react.tasks.GenerateEntryPointTask
|
||||
import com.facebook.react.tasks.GeneratePackageListTask
|
||||
import com.facebook.react.utils.AgpConfiguratorUtils.configureBuildConfigFieldsForApp
|
||||
import com.facebook.react.utils.AgpConfiguratorUtils.configureBuildConfigFieldsForLibraries
|
||||
import com.facebook.react.utils.AgpConfiguratorUtils.configureBuildTypesForApp
|
||||
import com.facebook.react.utils.AgpConfiguratorUtils.configureDevServerLocation
|
||||
import com.facebook.react.utils.AgpConfiguratorUtils.configureNamespaceForLibraries
|
||||
import com.facebook.react.utils.BackwardCompatUtils.configureBackwardCompatibilityReactMap
|
||||
@@ -85,7 +84,6 @@ class ReactPlugin : Plugin<Project> {
|
||||
configureAutolinking(project, extension)
|
||||
configureCodegen(project, extension, rootExtension, isLibrary = false)
|
||||
configureResources(project, extension)
|
||||
configureBuildTypesForApp(project)
|
||||
}
|
||||
|
||||
// Library Only Configuration
|
||||
|
||||
-21
@@ -19,7 +19,6 @@ import java.net.Inet4Address
|
||||
import java.net.NetworkInterface
|
||||
import javax.xml.parsers.DocumentBuilder
|
||||
import javax.xml.parsers.DocumentBuilderFactory
|
||||
import kotlin.plus
|
||||
import org.gradle.api.Action
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.api.plugins.AppliedPlugin
|
||||
@@ -28,26 +27,6 @@ import org.w3c.dom.Element
|
||||
@Suppress("UnstableApiUsage")
|
||||
internal object AgpConfiguratorUtils {
|
||||
|
||||
fun configureBuildTypesForApp(project: Project) {
|
||||
val action =
|
||||
Action<AppliedPlugin> {
|
||||
project.extensions
|
||||
.getByType(ApplicationAndroidComponentsExtension::class.java)
|
||||
.finalizeDsl { ext ->
|
||||
ext.buildTypes {
|
||||
val debug =
|
||||
getByName("debug").apply {
|
||||
manifestPlaceholders["usesCleartextTraffic"] = "true"
|
||||
}
|
||||
getByName("release").apply {
|
||||
manifestPlaceholders["usesCleartextTraffic"] = "false"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
project.pluginManager.withPlugin("com.android.application", action)
|
||||
}
|
||||
|
||||
fun configureBuildConfigFieldsForApp(project: Project, extension: ReactExtension) {
|
||||
val action =
|
||||
Action<AppliedPlugin> {
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
],
|
||||
"bugs": "https://github.com/facebook/react-native/issues",
|
||||
"engines": {
|
||||
"node": ">= 20.19.4"
|
||||
"node": ">= 22.14.0"
|
||||
},
|
||||
"exports": {
|
||||
".": "./src/index.js",
|
||||
|
||||
@@ -30,6 +30,6 @@
|
||||
}
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 20.19.4"
|
||||
"node": ">= 22.14.0"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,7 +16,6 @@ describe('console.timeStamp()', () => {
|
||||
});
|
||||
|
||||
it("doesn't throw when label is not specified", () => {
|
||||
// $FlowExpectedError[incompatible-call] not passing label intentionally
|
||||
expect(() => console.timeStamp()).not.toThrow();
|
||||
});
|
||||
|
||||
@@ -26,6 +25,7 @@ describe('console.timeStamp()', () => {
|
||||
|
||||
it("doesn't throw when additional arguments are specified", () => {
|
||||
expect(() =>
|
||||
// $FlowExpectedError[extra-arg]
|
||||
console.timeStamp('label', 100, 500, 'Track', 'Group', 'error'),
|
||||
).not.toThrow();
|
||||
});
|
||||
@@ -34,7 +34,7 @@ describe('console.timeStamp()', () => {
|
||||
// $FlowExpectedError[incompatible-call]
|
||||
expect(() => console.timeStamp({})).not.toThrow();
|
||||
expect(() =>
|
||||
// $FlowExpectedError[incompatible-call]
|
||||
// $FlowExpectedError[extra-arg]
|
||||
console.timeStamp('label', true, null, {}, [], () => {}),
|
||||
).not.toThrow();
|
||||
});
|
||||
|
||||
@@ -569,7 +569,10 @@ function consoleAssertPolyfill(expression, label) {
|
||||
}
|
||||
}
|
||||
|
||||
function stub() {}
|
||||
// https://developer.mozilla.org/en-US/docs/Web/API/console/timeStamp_static.
|
||||
// Non-standard API for recording markers on a timeline of the Performance instrumentation.
|
||||
// The actual logging is not provided by definition.
|
||||
function consoleTimeStampPolyfill() {}
|
||||
|
||||
if (global.nativeLoggingHook) {
|
||||
const originalConsole = global.console;
|
||||
@@ -582,11 +585,7 @@ if (global.nativeLoggingHook) {
|
||||
}
|
||||
|
||||
global.console = {
|
||||
time: stub,
|
||||
timeEnd: stub,
|
||||
timeStamp: stub,
|
||||
count: stub,
|
||||
countReset: stub,
|
||||
timeStamp: consoleTimeStampPolyfill,
|
||||
...(originalConsole ?? {}),
|
||||
error: getNativeLogFunction(LOG_LEVELS.error),
|
||||
info: getNativeLogFunction(LOG_LEVELS.info),
|
||||
@@ -677,6 +676,7 @@ if (global.nativeLoggingHook) {
|
||||
});
|
||||
}
|
||||
} else if (!global.console) {
|
||||
function stub() {}
|
||||
const log = global.print || stub;
|
||||
|
||||
global.console = {
|
||||
@@ -692,8 +692,6 @@ if (global.nativeLoggingHook) {
|
||||
}
|
||||
},
|
||||
clear: stub,
|
||||
count: stub,
|
||||
countReset: stub,
|
||||
dir: stub,
|
||||
dirxml: stub,
|
||||
group: stub,
|
||||
@@ -702,8 +700,6 @@ if (global.nativeLoggingHook) {
|
||||
profile: stub,
|
||||
profileEnd: stub,
|
||||
table: stub,
|
||||
time: stub,
|
||||
timeEnd: stub,
|
||||
timeStamp: stub,
|
||||
};
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
],
|
||||
"bugs": "https://github.com/facebook/react-native/issues",
|
||||
"engines": {
|
||||
"node": ">= 20.19.4"
|
||||
"node": ">= 22.14.0"
|
||||
},
|
||||
"files": [
|
||||
"console.js",
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
],
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 20.19.4"
|
||||
"node": ">= 22.14.0"
|
||||
},
|
||||
"main": "src/index.js",
|
||||
"files": [
|
||||
|
||||
+14
-22
@@ -38,6 +38,19 @@ function isFirstParty(fileName) {
|
||||
// use `this.foo = bar` instead of `this.defineProperty('foo', ...)`
|
||||
const loose = true;
|
||||
|
||||
const defaultPlugins = [
|
||||
[require('babel-plugin-syntax-hermes-parser'), {parseLangTypes: 'flow'}],
|
||||
[require('babel-plugin-transform-flow-enums')],
|
||||
[require('@babel/plugin-transform-block-scoping')],
|
||||
[require('@babel/plugin-transform-class-properties'), {loose}],
|
||||
[require('@babel/plugin-transform-private-methods'), {loose}],
|
||||
[require('@babel/plugin-transform-private-property-in-object'), {loose}],
|
||||
[require('@babel/plugin-syntax-dynamic-import')],
|
||||
[require('@babel/plugin-syntax-export-default-from')],
|
||||
...passthroughSyntaxPlugins,
|
||||
[require('@babel/plugin-transform-unicode-regex')],
|
||||
];
|
||||
|
||||
// For Static Hermes testing (experimental), the hermes-canary transformProfile
|
||||
// is used to enable regenerator (and some related lowering passes) because SH
|
||||
// requires more Babel lowering than Hermes temporarily.
|
||||
@@ -221,28 +234,7 @@ const getPreset = (src, options) => {
|
||||
plugins: [require('@babel/plugin-transform-flow-strip-types')],
|
||||
},
|
||||
{
|
||||
plugins: [
|
||||
[
|
||||
require('babel-plugin-syntax-hermes-parser'),
|
||||
{
|
||||
parseLangTypes: 'flow',
|
||||
reactRuntimeTarget: '19',
|
||||
...options.hermesParserOptions,
|
||||
},
|
||||
],
|
||||
[require('babel-plugin-transform-flow-enums')],
|
||||
[require('@babel/plugin-transform-block-scoping')],
|
||||
[require('@babel/plugin-transform-class-properties'), {loose}],
|
||||
[require('@babel/plugin-transform-private-methods'), {loose}],
|
||||
[
|
||||
require('@babel/plugin-transform-private-property-in-object'),
|
||||
{loose},
|
||||
],
|
||||
[require('@babel/plugin-syntax-dynamic-import')],
|
||||
[require('@babel/plugin-syntax-export-default-from')],
|
||||
...passthroughSyntaxPlugins,
|
||||
[require('@babel/plugin-transform-unicode-regex')],
|
||||
],
|
||||
plugins: defaultPlugins,
|
||||
},
|
||||
{
|
||||
test: isTypeScriptSource,
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
],
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 20.19.4"
|
||||
"node": ">= 22.14.0"
|
||||
},
|
||||
"main": "src/index.js",
|
||||
"files": [
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
],
|
||||
"bugs": "https://github.com/facebook/react-native/issues",
|
||||
"engines": {
|
||||
"node": ">= 20.19.4"
|
||||
"node": ">= 22.14.0"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "yarn clean && node scripts/build.js --verbose",
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
],
|
||||
"bugs": "https://github.com/facebook/react-native/issues",
|
||||
"engines": {
|
||||
"node": ">= 20.19.4"
|
||||
"node": ">= 22.14.0"
|
||||
},
|
||||
"exports": {
|
||||
".": "./src/index.js",
|
||||
|
||||
@@ -31,8 +31,12 @@ function mockQueueMicrotask() {
|
||||
}
|
||||
|
||||
describe('Animated', () => {
|
||||
let ReactNativeFeatureFlags;
|
||||
|
||||
beforeEach(() => {
|
||||
jest.resetModules();
|
||||
|
||||
ReactNativeFeatureFlags = require('../../../src/private/featureflags/ReactNativeFeatureFlags');
|
||||
});
|
||||
|
||||
mockQueueMicrotask();
|
||||
@@ -109,7 +113,50 @@ describe('Animated', () => {
|
||||
expect(callback.mock.calls.length).toBe(1);
|
||||
});
|
||||
|
||||
it('does not detach on updates', async () => {
|
||||
ReactNativeFeatureFlags.override({
|
||||
scheduleAnimatedCleanupInMicrotask: () => false,
|
||||
});
|
||||
|
||||
const opacity = new Animated.Value(0);
|
||||
jest.spyOn(opacity, '__detach');
|
||||
|
||||
const root = await create(<Animated.View style={{opacity}} />);
|
||||
expect(opacity.__detach).not.toBeCalled();
|
||||
|
||||
await update(root, <Animated.View style={{opacity}} />);
|
||||
expect(opacity.__detach).not.toBeCalled();
|
||||
|
||||
await unmount(root);
|
||||
expect(opacity.__detach).toBeCalled();
|
||||
});
|
||||
|
||||
it('stops animation when detached', async () => {
|
||||
ReactNativeFeatureFlags.override({
|
||||
scheduleAnimatedCleanupInMicrotask: () => false,
|
||||
});
|
||||
|
||||
const opacity = new Animated.Value(0);
|
||||
const callback = jest.fn();
|
||||
|
||||
const root = await create(<Animated.View style={{opacity}} />);
|
||||
|
||||
Animated.timing(opacity, {
|
||||
toValue: 10,
|
||||
duration: 1000,
|
||||
useNativeDriver: false,
|
||||
}).start(callback);
|
||||
|
||||
await unmount(root);
|
||||
|
||||
expect(callback).toBeCalledWith({finished: false});
|
||||
});
|
||||
|
||||
it('detaches only on unmount (in a microtask)', async () => {
|
||||
ReactNativeFeatureFlags.override({
|
||||
scheduleAnimatedCleanupInMicrotask: () => true,
|
||||
});
|
||||
|
||||
const opacity = new Animated.Value(0);
|
||||
jest.spyOn(opacity, '__detach');
|
||||
|
||||
@@ -128,6 +175,10 @@ describe('Animated', () => {
|
||||
});
|
||||
|
||||
it('restores default values only on update (in a microtask)', async () => {
|
||||
ReactNativeFeatureFlags.override({
|
||||
scheduleAnimatedCleanupInMicrotask: () => true,
|
||||
});
|
||||
|
||||
const __restoreDefaultValues = jest.spyOn(
|
||||
AnimatedProps.prototype,
|
||||
'__restoreDefaultValues',
|
||||
@@ -162,6 +213,10 @@ describe('Animated', () => {
|
||||
});
|
||||
|
||||
it('stops animation when detached (in a microtask)', async () => {
|
||||
ReactNativeFeatureFlags.override({
|
||||
scheduleAnimatedCleanupInMicrotask: () => true,
|
||||
});
|
||||
|
||||
const opacity = new Animated.Value(0);
|
||||
const callback = jest.fn();
|
||||
|
||||
|
||||
-1
@@ -49,7 +49,6 @@ function _defineCheckVersionTests() {
|
||||
// $FlowFixMe[cannot-write]
|
||||
console.error = jest.fn();
|
||||
// $FlowFixMe[cannot-write]
|
||||
// $FlowFixMe[unsafe-addition]
|
||||
global.console = {error: jest.fn(error => (consoleOutput += error))};
|
||||
spyOnConsoleError = jest.spyOn(global.console, 'error');
|
||||
});
|
||||
|
||||
@@ -8,13 +8,12 @@
|
||||
* @format
|
||||
*/
|
||||
|
||||
import Performance from '../../src/private/webapis/performance/Performance';
|
||||
import NativePerformance from '../../src/private/webapis/performance/specs/NativePerformance';
|
||||
|
||||
// In case if the native implementation of the Performance API is available, use it,
|
||||
// otherwise fall back to the legacy/default one, which only defines 'Performance.now()'
|
||||
if (NativePerformance) {
|
||||
const Performance =
|
||||
require('../../src/private/webapis/performance/Performance').default;
|
||||
// $FlowExpectedError[cannot-write]
|
||||
global.performance = new Performance();
|
||||
} else {
|
||||
|
||||
+171
-118
@@ -4,32 +4,180 @@
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @flow strict
|
||||
* @flow strict-local
|
||||
* @format
|
||||
*/
|
||||
|
||||
import type {EventSubscription} from '../vendor/emitter/EventEmitter';
|
||||
import type {Task} from './TaskQueue';
|
||||
|
||||
import * as ReactNativeFeatureFlags from '../../src/private/featureflags/ReactNativeFeatureFlags';
|
||||
import EventEmitter from '../vendor/emitter/EventEmitter';
|
||||
|
||||
const BatchedBridge = require('../BatchedBridge/BatchedBridge').default;
|
||||
const TaskQueue = require('./TaskQueue').default;
|
||||
const invariant = require('invariant');
|
||||
|
||||
export type SimpleTask = {
|
||||
name: string,
|
||||
run: () => void,
|
||||
};
|
||||
export type PromiseTask = {
|
||||
name: string,
|
||||
gen: () => Promise<void>,
|
||||
};
|
||||
export type Task = SimpleTask | PromiseTask | (() => void);
|
||||
export type {Task, SimpleTask, PromiseTask} from './TaskQueue';
|
||||
|
||||
export type Handle = number;
|
||||
|
||||
// NOTE: The original implementation of `InteractionManager` never rejected
|
||||
// the returned promise. This preserves that behavior in the stub.
|
||||
function reject(error: Error): void {
|
||||
setTimeout(() => {
|
||||
throw error;
|
||||
}, 0);
|
||||
const _emitter = new EventEmitter<{
|
||||
interactionComplete: [],
|
||||
interactionStart: [],
|
||||
}>();
|
||||
|
||||
const DEBUG_DELAY: 0 = 0;
|
||||
const DEBUG: false = false;
|
||||
|
||||
const InteractionManagerImpl = {
|
||||
Events: {
|
||||
interactionStart: 'interactionStart',
|
||||
interactionComplete: 'interactionComplete',
|
||||
},
|
||||
|
||||
/**
|
||||
* Schedule a function to run after all interactions have completed. Returns a cancellable
|
||||
* "promise".
|
||||
*/
|
||||
runAfterInteractions(task: ?Task): {
|
||||
then: <U>(
|
||||
onFulfill?: ?(void) => ?(Promise<U> | U),
|
||||
onReject?: ?(error: mixed) => ?(Promise<U> | U),
|
||||
) => Promise<U>,
|
||||
cancel: () => void,
|
||||
...
|
||||
} {
|
||||
const tasks: Array<Task> = [];
|
||||
const promise = new Promise((resolve: () => void) => {
|
||||
_scheduleUpdate();
|
||||
if (task) {
|
||||
tasks.push(task);
|
||||
}
|
||||
tasks.push({
|
||||
run: resolve,
|
||||
name: 'resolve ' + ((task && task.name) || '?'),
|
||||
});
|
||||
_taskQueue.enqueueTasks(tasks);
|
||||
});
|
||||
return {
|
||||
// $FlowFixMe[method-unbinding] added when improving typing for this parameters
|
||||
then: promise.then.bind(promise),
|
||||
cancel: function () {
|
||||
_taskQueue.cancelTasks(tasks);
|
||||
},
|
||||
};
|
||||
},
|
||||
|
||||
/**
|
||||
* Notify manager that an interaction has started.
|
||||
*/
|
||||
createInteractionHandle(): Handle {
|
||||
/* $FlowFixMe[constant-condition] Error discovered during Constant
|
||||
* Condition roll out. See https://fburl.com/workplace/1v97vimq. */
|
||||
DEBUG && console.log('InteractionManager: create interaction handle');
|
||||
_scheduleUpdate();
|
||||
const handle = ++_inc;
|
||||
_addInteractionSet.add(handle);
|
||||
return handle;
|
||||
},
|
||||
|
||||
/**
|
||||
* Notify manager that an interaction has completed.
|
||||
*/
|
||||
clearInteractionHandle(handle: Handle) {
|
||||
/* $FlowFixMe[constant-condition] Error discovered during Constant
|
||||
* Condition roll out. See https://fburl.com/workplace/1v97vimq. */
|
||||
DEBUG && console.log('InteractionManager: clear interaction handle');
|
||||
invariant(!!handle, 'InteractionManager: Must provide a handle to clear.');
|
||||
_scheduleUpdate();
|
||||
_addInteractionSet.delete(handle);
|
||||
_deleteInteractionSet.add(handle);
|
||||
},
|
||||
|
||||
// $FlowFixMe[unclear-type] unclear type of _emitter
|
||||
// $FlowFixMe[method-unbinding] added when improving typing for this parameters
|
||||
addListener: _emitter.addListener.bind(_emitter) as (
|
||||
eventType: string,
|
||||
// $FlowFixMe[unclear-type] unclear type of arguments
|
||||
listener: (...args: any) => mixed,
|
||||
context: mixed,
|
||||
) => EventSubscription,
|
||||
|
||||
/**
|
||||
* A positive number will use setTimeout to schedule any tasks after the
|
||||
* eventLoopRunningTime hits the deadline value, otherwise all tasks will be
|
||||
* executed in one setImmediate batch (default).
|
||||
*/
|
||||
setDeadline(deadline: number) {
|
||||
_deadline = deadline;
|
||||
},
|
||||
};
|
||||
|
||||
const _interactionSet = new Set<number | Handle>();
|
||||
const _addInteractionSet = new Set<number | Handle>();
|
||||
const _deleteInteractionSet = new Set<Handle>();
|
||||
const _taskQueue = new TaskQueue({onMoreTasks: _scheduleUpdate});
|
||||
let _nextUpdateHandle: $FlowFixMe | TimeoutID = 0;
|
||||
let _inc = 0;
|
||||
let _deadline = -1;
|
||||
|
||||
/**
|
||||
* Schedule an asynchronous update to the interaction state.
|
||||
*/
|
||||
function _scheduleUpdate() {
|
||||
if (!_nextUpdateHandle) {
|
||||
if (_deadline > 0) {
|
||||
_nextUpdateHandle = setTimeout(_processUpdate, 0 + DEBUG_DELAY);
|
||||
} else {
|
||||
_nextUpdateHandle = setImmediate(_processUpdate);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Notify listeners, process queue, etc
|
||||
*/
|
||||
function _processUpdate() {
|
||||
_nextUpdateHandle = 0;
|
||||
|
||||
const interactionCount = _interactionSet.size;
|
||||
_addInteractionSet.forEach(handle => _interactionSet.add(handle));
|
||||
_deleteInteractionSet.forEach(handle => _interactionSet.delete(handle));
|
||||
const nextInteractionCount = _interactionSet.size;
|
||||
|
||||
if (interactionCount !== 0 && nextInteractionCount === 0) {
|
||||
// transition from 1+ --> 0 interactions
|
||||
/* $FlowFixMe[prop-missing] Natural Inference rollout. See
|
||||
* https://fburl.com/workplace/6291gfvu */
|
||||
/* $FlowFixMe[invalid-computed-prop] Natural Inference rollout. See
|
||||
* https://fburl.com/workplace/6291gfvu */
|
||||
_emitter.emit(InteractionManager.Events.interactionComplete);
|
||||
} else if (interactionCount === 0 && nextInteractionCount !== 0) {
|
||||
// transition from 0 --> 1+ interactions
|
||||
/* $FlowFixMe[prop-missing] Natural Inference rollout. See
|
||||
* https://fburl.com/workplace/6291gfvu */
|
||||
/* $FlowFixMe[invalid-computed-prop] Natural Inference rollout. See
|
||||
* https://fburl.com/workplace/6291gfvu */
|
||||
_emitter.emit(InteractionManager.Events.interactionStart);
|
||||
}
|
||||
|
||||
// process the queue regardless of a transition
|
||||
if (nextInteractionCount === 0) {
|
||||
while (_taskQueue.hasTasksToProcess()) {
|
||||
_taskQueue.processNext();
|
||||
if (
|
||||
_deadline > 0 &&
|
||||
BatchedBridge.getEventLoopRunningTime() >= _deadline
|
||||
) {
|
||||
// Hit deadline before processing all tasks, so process more later.
|
||||
_scheduleUpdate();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
_addInteractionSet.clear();
|
||||
_deleteInteractionSet.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -83,106 +231,11 @@ function reject(error: Error): void {
|
||||
*
|
||||
* @deprecated
|
||||
*/
|
||||
const InteractionManagerStub = {
|
||||
Events: {
|
||||
interactionStart: 'interactionStart',
|
||||
interactionComplete: 'interactionComplete',
|
||||
},
|
||||
const InteractionManager = (
|
||||
ReactNativeFeatureFlags.disableInteractionManager()
|
||||
? // $FlowFixMe[incompatible-variance]
|
||||
require('./InteractionManagerStub').default
|
||||
: InteractionManagerImpl
|
||||
) as typeof InteractionManagerImpl;
|
||||
|
||||
/**
|
||||
* Schedule a function to run after all interactions have completed. Returns a cancellable
|
||||
* "promise".
|
||||
*
|
||||
* @deprecated
|
||||
*/
|
||||
runAfterInteractions(task: ?Task): {
|
||||
then: <U>(
|
||||
onFulfill?: ?(void) => ?(Promise<U> | U),
|
||||
onReject?: ?(error: mixed) => ?(Promise<U> | U),
|
||||
) => Promise<U>,
|
||||
cancel: () => void,
|
||||
...
|
||||
} {
|
||||
let immediateID: ?$FlowIssue;
|
||||
const promise = new Promise(resolve => {
|
||||
immediateID = setImmediate(() => {
|
||||
if (typeof task === 'object' && task !== null) {
|
||||
if (typeof task.gen === 'function') {
|
||||
task.gen().then(resolve, reject);
|
||||
} else if (typeof task.run === 'function') {
|
||||
try {
|
||||
task.run();
|
||||
resolve();
|
||||
} catch (error) {
|
||||
reject(error);
|
||||
}
|
||||
} else {
|
||||
reject(new TypeError(`Task "${task.name}" missing gen or run.`));
|
||||
}
|
||||
} else if (typeof task === 'function') {
|
||||
try {
|
||||
task();
|
||||
resolve();
|
||||
} catch (error) {
|
||||
reject(error);
|
||||
}
|
||||
} else {
|
||||
reject(new TypeError('Invalid task of type: ' + typeof task));
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
return {
|
||||
// $FlowFixMe[method-unbinding] added when improving typing for this parameters
|
||||
then: promise.then.bind(promise),
|
||||
cancel() {
|
||||
clearImmediate(immediateID);
|
||||
},
|
||||
};
|
||||
},
|
||||
|
||||
/**
|
||||
* Notify manager that an interaction has started.
|
||||
*
|
||||
* @deprecated
|
||||
*/
|
||||
createInteractionHandle(): Handle {
|
||||
return -1;
|
||||
},
|
||||
|
||||
/**
|
||||
* Notify manager that an interaction has completed.
|
||||
*
|
||||
* @deprecated
|
||||
*/
|
||||
clearInteractionHandle(handle: Handle) {
|
||||
invariant(!!handle, 'InteractionManager: Must provide a handle to clear.');
|
||||
},
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
*/
|
||||
addListener(
|
||||
eventType: string,
|
||||
// $FlowIgnore[unclear-type]
|
||||
listener: (...args: any) => mixed,
|
||||
context: mixed,
|
||||
): EventSubscription {
|
||||
return {
|
||||
remove() {},
|
||||
};
|
||||
},
|
||||
|
||||
/**
|
||||
* A positive number will use setTimeout to schedule any tasks after the
|
||||
* eventLoopRunningTime hits the deadline value, otherwise all tasks will be
|
||||
* executed in one setImmediate batch (default).
|
||||
*
|
||||
* @deprecated
|
||||
*/
|
||||
setDeadline(deadline: number) {
|
||||
// Do nothing.
|
||||
},
|
||||
};
|
||||
|
||||
export default InteractionManagerStub;
|
||||
export default InteractionManager;
|
||||
|
||||
@@ -0,0 +1,184 @@
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* @flow strict
|
||||
* @format
|
||||
*/
|
||||
|
||||
import type {EventSubscription} from '../vendor/emitter/EventEmitter';
|
||||
|
||||
const invariant = require('invariant');
|
||||
|
||||
export type Handle = number;
|
||||
|
||||
type Task =
|
||||
| {
|
||||
name: string,
|
||||
run: () => void,
|
||||
}
|
||||
| {
|
||||
name: string,
|
||||
gen: () => Promise<void>,
|
||||
}
|
||||
| (() => void);
|
||||
|
||||
// NOTE: The original implementation of `InteractionManager` never rejected
|
||||
// the returned promise. This preserves that behavior in the stub.
|
||||
function reject(error: Error): void {
|
||||
setTimeout(() => {
|
||||
throw error;
|
||||
}, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* InteractionManager allows long-running work to be scheduled after any
|
||||
* interactions/animations have completed. In particular, this allows JavaScript
|
||||
* animations to run smoothly.
|
||||
*
|
||||
* Applications can schedule tasks to run after interactions with the following:
|
||||
*
|
||||
* ```
|
||||
* InteractionManager.runAfterInteractions(() => {
|
||||
* // ...long-running synchronous task...
|
||||
* });
|
||||
* ```
|
||||
*
|
||||
* Compare this to other scheduling alternatives:
|
||||
*
|
||||
* - requestAnimationFrame(): for code that animates a view over time.
|
||||
* - setImmediate/setTimeout(): run code later, note this may delay animations.
|
||||
* - runAfterInteractions(): run code later, without delaying active animations.
|
||||
*
|
||||
* The touch handling system considers one or more active touches to be an
|
||||
* 'interaction' and will delay `runAfterInteractions()` callbacks until all
|
||||
* touches have ended or been cancelled.
|
||||
*
|
||||
* InteractionManager also allows applications to register animations by
|
||||
* creating an interaction 'handle' on animation start, and clearing it upon
|
||||
* completion:
|
||||
*
|
||||
* ```
|
||||
* var handle = InteractionManager.createInteractionHandle();
|
||||
* // run animation... (`runAfterInteractions` tasks are queued)
|
||||
* // later, on animation completion:
|
||||
* InteractionManager.clearInteractionHandle(handle);
|
||||
* // queued tasks run if all handles were cleared
|
||||
* ```
|
||||
*
|
||||
* `runAfterInteractions` takes either a plain callback function, or a
|
||||
* `PromiseTask` object with a `gen` method that returns a `Promise`. If a
|
||||
* `PromiseTask` is supplied, then it is fully resolved (including asynchronous
|
||||
* dependencies that also schedule more tasks via `runAfterInteractions`) before
|
||||
* starting on the next task that might have been queued up synchronously
|
||||
* earlier.
|
||||
*
|
||||
* By default, queued tasks are executed together in a loop in one
|
||||
* `setImmediate` batch. If `setDeadline` is called with a positive number, then
|
||||
* tasks will only be executed until the deadline (in terms of js event loop run
|
||||
* time) approaches, at which point execution will yield via setTimeout,
|
||||
* allowing events such as touches to start interactions and block queued tasks
|
||||
* from executing, making apps more responsive.
|
||||
*
|
||||
* @deprecated
|
||||
*/
|
||||
const InteractionManagerStub = {
|
||||
Events: {
|
||||
interactionStart: 'interactionStart',
|
||||
interactionComplete: 'interactionComplete',
|
||||
},
|
||||
|
||||
/**
|
||||
* Schedule a function to run after all interactions have completed. Returns a cancellable
|
||||
* "promise".
|
||||
*
|
||||
* @deprecated
|
||||
*/
|
||||
runAfterInteractions(task: ?Task): {
|
||||
then: <U>(
|
||||
onFulfill?: ?(void) => ?(Promise<U> | U),
|
||||
onReject?: ?(error: mixed) => ?(Promise<U> | U),
|
||||
) => Promise<U>,
|
||||
cancel: () => void,
|
||||
...
|
||||
} {
|
||||
let immediateID: ?$FlowIssue;
|
||||
const promise = new Promise(resolve => {
|
||||
immediateID = setImmediate(() => {
|
||||
if (typeof task === 'object' && task !== null) {
|
||||
if (typeof task.gen === 'function') {
|
||||
task.gen().then(resolve, reject);
|
||||
} else if (typeof task.run === 'function') {
|
||||
try {
|
||||
task.run();
|
||||
resolve();
|
||||
} catch (error) {
|
||||
reject(error);
|
||||
}
|
||||
} else {
|
||||
reject(new TypeError(`Task "${task.name}" missing gen or run.`));
|
||||
}
|
||||
} else if (typeof task === 'function') {
|
||||
try {
|
||||
task();
|
||||
resolve();
|
||||
} catch (error) {
|
||||
reject(error);
|
||||
}
|
||||
} else {
|
||||
reject(new TypeError('Invalid task of type: ' + typeof task));
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
return {
|
||||
// $FlowFixMe[method-unbinding] added when improving typing for this parameters
|
||||
then: promise.then.bind(promise),
|
||||
cancel() {
|
||||
clearImmediate(immediateID);
|
||||
},
|
||||
};
|
||||
},
|
||||
|
||||
/**
|
||||
* Notify manager that an interaction has started.
|
||||
*
|
||||
* @deprecated
|
||||
*/
|
||||
createInteractionHandle(): Handle {
|
||||
return -1;
|
||||
},
|
||||
|
||||
/**
|
||||
* Notify manager that an interaction has completed.
|
||||
*
|
||||
* @deprecated
|
||||
*/
|
||||
clearInteractionHandle(handle: Handle) {
|
||||
invariant(!!handle, 'InteractionManager: Must provide a handle to clear.');
|
||||
},
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
*/
|
||||
addListener(): EventSubscription {
|
||||
return {
|
||||
remove() {},
|
||||
};
|
||||
},
|
||||
|
||||
/**
|
||||
* A positive number will use setTimeout to schedule any tasks after the
|
||||
* eventLoopRunningTime hits the deadline value, otherwise all tasks will be
|
||||
* executed in one setImmediate batch (default).
|
||||
*
|
||||
* @deprecated
|
||||
*/
|
||||
setDeadline(deadline: number) {
|
||||
// Do nothing.
|
||||
},
|
||||
};
|
||||
|
||||
export default InteractionManagerStub;
|
||||
@@ -0,0 +1,197 @@
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* @flow strict
|
||||
* @format
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
const invariant = require('invariant');
|
||||
|
||||
export type SimpleTask = {
|
||||
name: string,
|
||||
run: () => void,
|
||||
};
|
||||
export type PromiseTask = {
|
||||
name: string,
|
||||
gen: () => Promise<void>,
|
||||
};
|
||||
export type Task = SimpleTask | PromiseTask | (() => void);
|
||||
|
||||
const DEBUG: false = false;
|
||||
|
||||
/**
|
||||
* TaskQueue - A system for queueing and executing a mix of simple callbacks and
|
||||
* trees of dependent tasks based on Promises. No tasks are executed unless
|
||||
* `processNext` is called.
|
||||
*
|
||||
* `enqueue` takes a Task object with either a simple `run` callback, or a
|
||||
* `gen` function that returns a `Promise` and puts it in the queue. If a gen
|
||||
* function is supplied, then the promise it returns will block execution of
|
||||
* tasks already in the queue until it resolves. This can be used to make sure
|
||||
* the first task is fully resolved (including asynchronous dependencies that
|
||||
* also schedule more tasks via `enqueue`) before starting on the next task.
|
||||
* The `onMoreTasks` constructor argument is used to inform the owner that an
|
||||
* async task has resolved and that the queue should be processed again.
|
||||
*
|
||||
* Note: Tasks are only actually executed with explicit calls to `processNext`.
|
||||
*/
|
||||
class TaskQueue {
|
||||
/**
|
||||
* TaskQueue instances are self contained and independent, so multiple tasks
|
||||
* of varying semantics and priority can operate together.
|
||||
*
|
||||
* `onMoreTasks` is invoked when `PromiseTask`s resolve if there are more
|
||||
* tasks to process.
|
||||
*/
|
||||
constructor({onMoreTasks}: {onMoreTasks: () => void, ...}) {
|
||||
this._onMoreTasks = onMoreTasks;
|
||||
this._queueStack = [{tasks: [], popable: false}];
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a task to the queue. It is recommended to name your tasks for easier
|
||||
* async debugging. Tasks will not be executed until `processNext` is called
|
||||
* explicitly.
|
||||
*/
|
||||
enqueue(task: Task): void {
|
||||
this._getCurrentQueue().push(task);
|
||||
}
|
||||
|
||||
enqueueTasks(tasks: Array<Task>): void {
|
||||
tasks.forEach(task => this.enqueue(task));
|
||||
}
|
||||
|
||||
cancelTasks(tasksToCancel: Array<Task>): void {
|
||||
// search through all tasks and remove them.
|
||||
this._queueStack = this._queueStack
|
||||
.map(queue => ({
|
||||
...queue,
|
||||
tasks: queue.tasks.filter(task => tasksToCancel.indexOf(task) === -1),
|
||||
}))
|
||||
.filter((queue, idx) => queue.tasks.length > 0 || idx === 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check to see if `processNext` should be called.
|
||||
*
|
||||
* @returns {boolean} Returns true if there are tasks that are ready to be
|
||||
* processed with `processNext`, or returns false if there are no more tasks
|
||||
* to be processed right now, although there may be tasks in the queue that
|
||||
* are blocked by earlier `PromiseTask`s that haven't resolved yet.
|
||||
* `onMoreTasks` will be called after each `PromiseTask` resolves if there are
|
||||
* tasks ready to run at that point.
|
||||
*/
|
||||
hasTasksToProcess(): boolean {
|
||||
return this._getCurrentQueue().length > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes the next task in the queue.
|
||||
*/
|
||||
processNext(): void {
|
||||
const queue = this._getCurrentQueue();
|
||||
if (queue.length) {
|
||||
const task = queue.shift();
|
||||
try {
|
||||
if (typeof task === 'object' && task.gen) {
|
||||
/* $FlowFixMe[constant-condition] Error discovered during Constant
|
||||
* Condition roll out. See https://fburl.com/workplace/1v97vimq. */
|
||||
DEBUG && console.log('TaskQueue: genPromise for task ' + task.name);
|
||||
this._genPromise(task);
|
||||
} else if (typeof task === 'object' && task.run) {
|
||||
/* $FlowFixMe[constant-condition] Error discovered during Constant
|
||||
* Condition roll out. See https://fburl.com/workplace/1v97vimq. */
|
||||
DEBUG && console.log('TaskQueue: run task ' + task.name);
|
||||
task.run();
|
||||
} else {
|
||||
invariant(
|
||||
typeof task === 'function',
|
||||
'Expected Function, SimpleTask, or PromiseTask, but got:\n' +
|
||||
JSON.stringify(task, null, 2),
|
||||
);
|
||||
/* $FlowFixMe[constant-condition] Error discovered during Constant
|
||||
* Condition roll out. See https://fburl.com/workplace/1v97vimq. */
|
||||
DEBUG && console.log('TaskQueue: run anonymous task');
|
||||
task();
|
||||
}
|
||||
} catch (e) {
|
||||
e.message =
|
||||
// $FlowFixMe[incompatible-type]
|
||||
// $FlowFixMe[incompatible-use]
|
||||
'TaskQueue: Error with task ' + (task.name || '') + ': ' + e.message;
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_queueStack: Array<{
|
||||
tasks: Array<Task>,
|
||||
popable: boolean,
|
||||
...
|
||||
}>;
|
||||
_onMoreTasks: () => void;
|
||||
|
||||
_getCurrentQueue(): Array<Task> {
|
||||
const stackIdx = this._queueStack.length - 1;
|
||||
const queue = this._queueStack[stackIdx];
|
||||
if (
|
||||
queue.popable &&
|
||||
queue.tasks.length === 0 &&
|
||||
this._queueStack.length > 1
|
||||
) {
|
||||
this._queueStack.pop();
|
||||
/* $FlowFixMe[constant-condition] Error discovered during Constant
|
||||
* Condition roll out. See https://fburl.com/workplace/1v97vimq. */
|
||||
DEBUG &&
|
||||
console.log('TaskQueue: popped queue: ', {
|
||||
stackIdx,
|
||||
queueStackSize: this._queueStack.length,
|
||||
});
|
||||
return this._getCurrentQueue();
|
||||
} else {
|
||||
return queue.tasks;
|
||||
}
|
||||
}
|
||||
|
||||
_genPromise(task: PromiseTask) {
|
||||
// Each async task pushes it's own queue onto the queue stack. This
|
||||
// effectively defers execution of previously queued tasks until the promise
|
||||
// resolves, at which point we allow the new queue to be popped, which
|
||||
// happens once it is fully processed.
|
||||
this._queueStack.push({tasks: [], popable: false});
|
||||
const stackIdx = this._queueStack.length - 1;
|
||||
const stackItem = this._queueStack[stackIdx];
|
||||
/* $FlowFixMe[constant-condition] Error discovered during Constant
|
||||
* Condition roll out. See https://fburl.com/workplace/1v97vimq. */
|
||||
DEBUG && console.log('TaskQueue: push new queue: ', {stackIdx});
|
||||
/* $FlowFixMe[constant-condition] Error discovered during Constant
|
||||
* Condition roll out. See https://fburl.com/workplace/1v97vimq. */
|
||||
DEBUG && console.log('TaskQueue: exec gen task ' + task.name);
|
||||
task
|
||||
.gen()
|
||||
.then(() => {
|
||||
/* $FlowFixMe[constant-condition] Error discovered during Constant
|
||||
* Condition roll out. See https://fburl.com/workplace/1v97vimq. */
|
||||
DEBUG &&
|
||||
console.log('TaskQueue: onThen for gen task ' + task.name, {
|
||||
stackIdx,
|
||||
queueStackSize: this._queueStack.length,
|
||||
});
|
||||
stackItem.popable = true;
|
||||
this.hasTasksToProcess() && this._onMoreTasks();
|
||||
})
|
||||
.catch(ex => {
|
||||
setTimeout(() => {
|
||||
ex.message = `TaskQueue: Error resolving Promise in task ${task.name}: ${ex.message}`;
|
||||
throw ex;
|
||||
}, 0);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export default TaskQueue;
|
||||
+342
@@ -0,0 +1,342 @@
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* @noflow
|
||||
* @format
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
import type {ReactNativeFeatureFlagsJsOnlyOverrides} from '../../../src/private/featureflags/ReactNativeFeatureFlags';
|
||||
|
||||
function importModules(overrides: ReactNativeFeatureFlagsJsOnlyOverrides) {
|
||||
const ReactNativeFeatureFlags = require('../../../src/private/featureflags/ReactNativeFeatureFlags');
|
||||
|
||||
// Make sure to setup overrides before importing any modules.
|
||||
ReactNativeFeatureFlags.override(overrides);
|
||||
|
||||
const BatchedBridge = require('../../BatchedBridge/BatchedBridge').default;
|
||||
const InteractionManager = require('../InteractionManager').default;
|
||||
|
||||
jest.mock('../../vendor/core/ErrorUtils');
|
||||
jest.mock('../../BatchedBridge/BatchedBridge');
|
||||
|
||||
return {
|
||||
BatchedBridge,
|
||||
InteractionManager,
|
||||
};
|
||||
}
|
||||
|
||||
const isWindows = process.platform === 'win32';
|
||||
const itif = (condition: boolean) => (condition ? it : it.skip);
|
||||
|
||||
function expectToBeCalledOnce(
|
||||
fn: JestMockFn<$ReadOnlyArray<mixed>, mixed>,
|
||||
): void {
|
||||
expect(fn.mock.calls.length).toBe(1);
|
||||
}
|
||||
|
||||
describe('InteractionManager', () => {
|
||||
let InteractionManager;
|
||||
let interactionStart;
|
||||
let interactionComplete;
|
||||
|
||||
beforeEach(() => {
|
||||
jest.resetModules();
|
||||
({InteractionManager} = importModules({
|
||||
disableInteractionManager: () => false,
|
||||
}));
|
||||
|
||||
interactionStart = jest.fn();
|
||||
interactionComplete = jest.fn();
|
||||
|
||||
InteractionManager.addListener(
|
||||
InteractionManager.Events.interactionStart,
|
||||
interactionStart,
|
||||
);
|
||||
InteractionManager.addListener(
|
||||
InteractionManager.Events.interactionComplete,
|
||||
interactionComplete,
|
||||
);
|
||||
});
|
||||
|
||||
it('throws when clearing an undefined handle', () => {
|
||||
// $FlowExpectedError[incompatible-call]
|
||||
expect(() => InteractionManager.clearInteractionHandle()).toThrow();
|
||||
});
|
||||
|
||||
it('notifies asynchronously when interaction starts', () => {
|
||||
InteractionManager.createInteractionHandle();
|
||||
expect(interactionStart).not.toBeCalled();
|
||||
|
||||
jest.runAllTimers();
|
||||
expect(interactionStart).toBeCalled();
|
||||
expect(interactionComplete).not.toBeCalled();
|
||||
});
|
||||
|
||||
it('notifies asynchronously when interaction stops', () => {
|
||||
const handle = InteractionManager.createInteractionHandle();
|
||||
jest.runAllTimers();
|
||||
interactionStart.mockClear();
|
||||
InteractionManager.clearInteractionHandle(handle);
|
||||
expect(interactionComplete).not.toBeCalled();
|
||||
|
||||
jest.runAllTimers();
|
||||
expect(interactionStart).not.toBeCalled();
|
||||
expect(interactionComplete).toBeCalled();
|
||||
});
|
||||
|
||||
it('does not notify when started & stopped in same event loop', () => {
|
||||
const handle = InteractionManager.createInteractionHandle();
|
||||
InteractionManager.clearInteractionHandle(handle);
|
||||
|
||||
jest.runAllTimers();
|
||||
expect(interactionStart).not.toBeCalled();
|
||||
expect(interactionComplete).not.toBeCalled();
|
||||
});
|
||||
|
||||
it('does not notify when going from two -> one active interactions', () => {
|
||||
InteractionManager.createInteractionHandle();
|
||||
const handle = InteractionManager.createInteractionHandle();
|
||||
jest.runAllTimers();
|
||||
|
||||
interactionStart.mockClear();
|
||||
interactionComplete.mockClear();
|
||||
|
||||
InteractionManager.clearInteractionHandle(handle);
|
||||
jest.runAllTimers();
|
||||
expect(interactionStart).not.toBeCalled();
|
||||
expect(interactionComplete).not.toBeCalled();
|
||||
});
|
||||
|
||||
it('runs tasks asynchronously when there are interactions', () => {
|
||||
const task = jest.fn();
|
||||
InteractionManager.runAfterInteractions(task);
|
||||
expect(task).not.toBeCalled();
|
||||
|
||||
jest.runAllTimers();
|
||||
expect(task).toBeCalled();
|
||||
});
|
||||
|
||||
it('runs tasks when interactions complete', () => {
|
||||
const task = jest.fn();
|
||||
const handle = InteractionManager.createInteractionHandle();
|
||||
InteractionManager.runAfterInteractions(task);
|
||||
|
||||
jest.runAllTimers();
|
||||
InteractionManager.clearInteractionHandle(handle);
|
||||
expect(task).not.toBeCalled();
|
||||
|
||||
jest.runAllTimers();
|
||||
expect(task).toBeCalled();
|
||||
});
|
||||
|
||||
it('does not run tasks twice', () => {
|
||||
const task1 = jest.fn();
|
||||
const task2 = jest.fn();
|
||||
InteractionManager.runAfterInteractions(task1);
|
||||
jest.runAllTimers();
|
||||
|
||||
InteractionManager.runAfterInteractions(task2);
|
||||
jest.runAllTimers();
|
||||
|
||||
expectToBeCalledOnce(task1);
|
||||
});
|
||||
|
||||
it('runs tasks added while processing previous tasks', () => {
|
||||
const task1 = jest.fn(() => {
|
||||
InteractionManager.runAfterInteractions(task2);
|
||||
});
|
||||
const task2 = jest.fn();
|
||||
|
||||
InteractionManager.runAfterInteractions(task1);
|
||||
expect(task2).not.toBeCalled();
|
||||
|
||||
jest.runAllTimers();
|
||||
|
||||
expect(task1).toBeCalled();
|
||||
expect(task2).toBeCalled();
|
||||
});
|
||||
|
||||
it('allows tasks to be cancelled', () => {
|
||||
const task1 = jest.fn();
|
||||
const task2 = jest.fn();
|
||||
const promise1 = InteractionManager.runAfterInteractions(task1);
|
||||
InteractionManager.runAfterInteractions(task2);
|
||||
expect(task1).not.toBeCalled();
|
||||
expect(task2).not.toBeCalled();
|
||||
promise1.cancel();
|
||||
|
||||
jest.runAllTimers();
|
||||
expect(task1).not.toBeCalled();
|
||||
expect(task2).toBeCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe('promise tasks', () => {
|
||||
let BatchedBridge;
|
||||
let InteractionManager;
|
||||
let sequenceId;
|
||||
|
||||
function createSequenceTask(expectedSequenceId: number) {
|
||||
return jest.fn(() => {
|
||||
expect(++sequenceId).toBe(expectedSequenceId);
|
||||
});
|
||||
}
|
||||
|
||||
beforeEach(() => {
|
||||
jest.resetModules();
|
||||
|
||||
({BatchedBridge, InteractionManager} = importModules({
|
||||
disableInteractionManager: () => false,
|
||||
}));
|
||||
|
||||
sequenceId = 0;
|
||||
});
|
||||
|
||||
it('should run a basic promise task', () => {
|
||||
const task1 = jest.fn(() => {
|
||||
expect(++sequenceId).toBe(1);
|
||||
return new Promise(resolve => resolve());
|
||||
});
|
||||
InteractionManager.runAfterInteractions({gen: task1, name: 'gen1'});
|
||||
jest.runAllTimers();
|
||||
expectToBeCalledOnce(task1);
|
||||
});
|
||||
|
||||
it('should handle nested promises', () => {
|
||||
const task1 = jest.fn(() => {
|
||||
expect(++sequenceId).toBe(1);
|
||||
return new Promise(resolve => {
|
||||
InteractionManager.runAfterInteractions({
|
||||
gen: task2,
|
||||
name: 'gen2',
|
||||
}).then(resolve);
|
||||
});
|
||||
});
|
||||
const task2 = jest.fn(() => {
|
||||
expect(++sequenceId).toBe(2);
|
||||
return new Promise(resolve => resolve());
|
||||
});
|
||||
InteractionManager.runAfterInteractions({gen: task1, name: 'gen1'});
|
||||
jest.runAllTimers();
|
||||
expectToBeCalledOnce(task1);
|
||||
expectToBeCalledOnce(task2);
|
||||
});
|
||||
|
||||
it('should pause promise tasks during interactions then resume', () => {
|
||||
const task1 = createSequenceTask(1);
|
||||
const task2 = jest.fn(() => {
|
||||
expect(++sequenceId).toBe(2);
|
||||
return new Promise(resolve => {
|
||||
setTimeout(() => {
|
||||
InteractionManager.runAfterInteractions(task3).then(resolve);
|
||||
}, 1);
|
||||
});
|
||||
});
|
||||
const task3 = createSequenceTask(3);
|
||||
InteractionManager.runAfterInteractions(task1);
|
||||
InteractionManager.runAfterInteractions({gen: task2, name: 'gen2'});
|
||||
jest.runOnlyPendingTimers();
|
||||
expectToBeCalledOnce(task1);
|
||||
expectToBeCalledOnce(task2);
|
||||
const handle = InteractionManager.createInteractionHandle();
|
||||
jest.runAllTimers();
|
||||
jest.runAllTimers(); // Just to be sure...
|
||||
expect(task3).not.toBeCalled();
|
||||
InteractionManager.clearInteractionHandle(handle);
|
||||
jest.runAllTimers();
|
||||
expectToBeCalledOnce(task3);
|
||||
});
|
||||
|
||||
it('should execute tasks in loop within deadline', () => {
|
||||
InteractionManager.setDeadline(100);
|
||||
BatchedBridge.getEventLoopRunningTime.mockReturnValue(10);
|
||||
const task1 = createSequenceTask(1);
|
||||
const task2 = createSequenceTask(2);
|
||||
InteractionManager.runAfterInteractions(task1);
|
||||
InteractionManager.runAfterInteractions(task2);
|
||||
|
||||
jest.runOnlyPendingTimers();
|
||||
|
||||
expectToBeCalledOnce(task1);
|
||||
expectToBeCalledOnce(task2);
|
||||
});
|
||||
|
||||
it('should execute tasks one at a time if deadline exceeded', () => {
|
||||
InteractionManager.setDeadline(100);
|
||||
BatchedBridge.getEventLoopRunningTime.mockReturnValue(200);
|
||||
const task1 = createSequenceTask(1);
|
||||
const task2 = createSequenceTask(2);
|
||||
InteractionManager.runAfterInteractions(task1);
|
||||
InteractionManager.runAfterInteractions(task2);
|
||||
|
||||
jest.runOnlyPendingTimers();
|
||||
|
||||
expectToBeCalledOnce(task1);
|
||||
expect(task2).not.toBeCalled();
|
||||
|
||||
jest.runOnlyPendingTimers(); // resolve1
|
||||
jest.runOnlyPendingTimers(); // task2
|
||||
|
||||
expectToBeCalledOnce(task2);
|
||||
});
|
||||
|
||||
const bigAsyncTest = resolveTest => {
|
||||
jest.useRealTimers();
|
||||
|
||||
const task1 = createSequenceTask(1);
|
||||
const task2 = jest.fn(() => {
|
||||
expect(++sequenceId).toBe(2);
|
||||
return new Promise(resolve => {
|
||||
InteractionManager.runAfterInteractions(task3);
|
||||
setTimeout(() => {
|
||||
InteractionManager.runAfterInteractions({
|
||||
gen: task4,
|
||||
name: 'gen4',
|
||||
}).then(resolve);
|
||||
}, 1);
|
||||
});
|
||||
});
|
||||
const task3 = createSequenceTask(3);
|
||||
const task4 = jest.fn(() => {
|
||||
expect(++sequenceId).toBe(4);
|
||||
return new Promise(resolve => {
|
||||
InteractionManager.runAfterInteractions(task5).then(resolve);
|
||||
});
|
||||
});
|
||||
const task5 = createSequenceTask(5);
|
||||
const task6 = createSequenceTask(6);
|
||||
|
||||
InteractionManager.runAfterInteractions(task1);
|
||||
InteractionManager.runAfterInteractions({gen: task2, name: 'gen2'});
|
||||
InteractionManager.runAfterInteractions(task6);
|
||||
|
||||
setTimeout(() => {
|
||||
expectToBeCalledOnce(task1);
|
||||
expectToBeCalledOnce(task2);
|
||||
expectToBeCalledOnce(task3);
|
||||
expectToBeCalledOnce(task4);
|
||||
expectToBeCalledOnce(task5);
|
||||
expectToBeCalledOnce(task6);
|
||||
|
||||
resolveTest();
|
||||
}, 100);
|
||||
};
|
||||
|
||||
itif(!isWindows)(
|
||||
'resolves async tasks recursively before other queued tasks',
|
||||
() => {
|
||||
return new Promise(bigAsyncTest);
|
||||
},
|
||||
);
|
||||
|
||||
itif(!isWindows)('should also work with a deadline', () => {
|
||||
InteractionManager.setDeadline(100);
|
||||
BatchedBridge.getEventLoopRunningTime.mockReturnValue(200);
|
||||
return new Promise(bigAsyncTest);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,169 @@
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* @noflow
|
||||
* @format
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
const Promise = require('promise');
|
||||
|
||||
function expectToBeCalledOnce(fn) {
|
||||
expect(fn.mock.calls.length).toBe(1);
|
||||
}
|
||||
|
||||
function clearTaskQueue(taskQueue) {
|
||||
do {
|
||||
jest.runAllTimers();
|
||||
taskQueue.processNext();
|
||||
jest.runAllTimers();
|
||||
} while (taskQueue.hasTasksToProcess());
|
||||
}
|
||||
|
||||
describe('TaskQueue', () => {
|
||||
let taskQueue;
|
||||
let onMoreTasks;
|
||||
let sequenceId;
|
||||
function createSequenceTask(expectedSequenceId) {
|
||||
return jest.fn(() => {
|
||||
expect(++sequenceId).toBe(expectedSequenceId);
|
||||
});
|
||||
}
|
||||
beforeEach(() => {
|
||||
jest.resetModules();
|
||||
onMoreTasks = jest.fn();
|
||||
const TaskQueue = require('../TaskQueue').default;
|
||||
taskQueue = new TaskQueue({onMoreTasks});
|
||||
sequenceId = 0;
|
||||
});
|
||||
|
||||
it('should run a basic task', () => {
|
||||
const task1 = createSequenceTask(1);
|
||||
taskQueue.enqueue({run: task1, name: 'run1'});
|
||||
expect(taskQueue.hasTasksToProcess()).toBe(true);
|
||||
taskQueue.processNext();
|
||||
expectToBeCalledOnce(task1);
|
||||
});
|
||||
|
||||
it('should handle blocking promise task', () => {
|
||||
const task1 = jest.fn(() => {
|
||||
return new Promise(resolve => {
|
||||
setTimeout(() => {
|
||||
expect(++sequenceId).toBe(1);
|
||||
resolve();
|
||||
}, 1);
|
||||
});
|
||||
});
|
||||
const task2 = createSequenceTask(2);
|
||||
taskQueue.enqueue({gen: task1, name: 'gen1'});
|
||||
taskQueue.enqueue({run: task2, name: 'run2'});
|
||||
|
||||
taskQueue.processNext();
|
||||
|
||||
expectToBeCalledOnce(task1);
|
||||
expect(task2).not.toBeCalled();
|
||||
expect(onMoreTasks).not.toBeCalled();
|
||||
expect(taskQueue.hasTasksToProcess()).toBe(false);
|
||||
|
||||
clearTaskQueue(taskQueue);
|
||||
|
||||
expectToBeCalledOnce(onMoreTasks);
|
||||
expectToBeCalledOnce(task2);
|
||||
});
|
||||
|
||||
it('should handle nested simple tasks', () => {
|
||||
const task1 = jest.fn(() => {
|
||||
expect(++sequenceId).toBe(1);
|
||||
taskQueue.enqueue({run: task3, name: 'run3'});
|
||||
});
|
||||
const task2 = createSequenceTask(2);
|
||||
const task3 = createSequenceTask(3);
|
||||
taskQueue.enqueue({run: task1, name: 'run1'});
|
||||
taskQueue.enqueue({run: task2, name: 'run2'}); // not blocked by task 1
|
||||
|
||||
clearTaskQueue(taskQueue);
|
||||
|
||||
expectToBeCalledOnce(task1);
|
||||
expectToBeCalledOnce(task2);
|
||||
expectToBeCalledOnce(task3);
|
||||
});
|
||||
|
||||
it('should handle nested promises', () => {
|
||||
const task1 = jest.fn(() => {
|
||||
return new Promise(resolve => {
|
||||
setTimeout(() => {
|
||||
expect(++sequenceId).toBe(1);
|
||||
taskQueue.enqueue({gen: task2, name: 'gen2'});
|
||||
taskQueue.enqueue({run: resolve, name: 'resolve1'});
|
||||
}, 1);
|
||||
});
|
||||
});
|
||||
const task2 = jest.fn(() => {
|
||||
return new Promise(resolve => {
|
||||
setTimeout(() => {
|
||||
expect(++sequenceId).toBe(2);
|
||||
taskQueue.enqueue({run: task3, name: 'run3'});
|
||||
taskQueue.enqueue({run: resolve, name: 'resolve2'});
|
||||
}, 1);
|
||||
});
|
||||
});
|
||||
const task3 = createSequenceTask(3);
|
||||
const task4 = createSequenceTask(4);
|
||||
taskQueue.enqueue({gen: task1, name: 'gen1'});
|
||||
taskQueue.enqueue({run: task4, name: 'run4'}); // blocked by task 1 promise
|
||||
|
||||
clearTaskQueue(taskQueue);
|
||||
|
||||
expectToBeCalledOnce(task1);
|
||||
expectToBeCalledOnce(task2);
|
||||
expectToBeCalledOnce(task3);
|
||||
expectToBeCalledOnce(task4);
|
||||
});
|
||||
|
||||
it('should be able to cancel tasks', () => {
|
||||
const task1 = jest.fn();
|
||||
const task2 = createSequenceTask(1);
|
||||
const task3 = jest.fn();
|
||||
const task4 = createSequenceTask(2);
|
||||
taskQueue.enqueue(task1);
|
||||
taskQueue.enqueue(task2);
|
||||
taskQueue.enqueue(task3);
|
||||
taskQueue.enqueue(task4);
|
||||
taskQueue.cancelTasks([task1, task3]);
|
||||
clearTaskQueue(taskQueue);
|
||||
expect(task1).not.toBeCalled();
|
||||
expect(task3).not.toBeCalled();
|
||||
expectToBeCalledOnce(task2);
|
||||
expectToBeCalledOnce(task4);
|
||||
expect(taskQueue.hasTasksToProcess()).toBe(false);
|
||||
});
|
||||
|
||||
it('should not crash when last task is cancelled', () => {
|
||||
const task1 = jest.fn();
|
||||
taskQueue.enqueue(task1);
|
||||
taskQueue.cancelTasks([task1]);
|
||||
clearTaskQueue(taskQueue);
|
||||
expect(task1).not.toBeCalled();
|
||||
expect(taskQueue.hasTasksToProcess()).toBe(false);
|
||||
});
|
||||
|
||||
it('should not crash when task is cancelled between being started and resolved', () => {
|
||||
const task1 = jest.fn(() => {
|
||||
return new Promise(resolve => {
|
||||
setTimeout(() => {
|
||||
resolve();
|
||||
}, 1);
|
||||
});
|
||||
});
|
||||
|
||||
taskQueue.enqueue({gen: task1, name: 'gen1'});
|
||||
taskQueue.processNext();
|
||||
taskQueue.cancelTasks([task1]);
|
||||
|
||||
jest.runAllTimers();
|
||||
});
|
||||
});
|
||||
@@ -400,6 +400,7 @@ class XMLHttpRequest extends EventTarget {
|
||||
if (XMLHttpRequest._profiling) {
|
||||
console.timeStamp(
|
||||
'Incremental Data: ' + this._getMeasureURL(),
|
||||
// $FlowFixMe[extra-arg] Add correct typing for `console.timeStamp`
|
||||
start,
|
||||
undefined,
|
||||
PERFORMANCE_TRACK_NAME,
|
||||
@@ -454,6 +455,7 @@ class XMLHttpRequest extends EventTarget {
|
||||
const start = this._startTime;
|
||||
console.timeStamp(
|
||||
this._getMeasureURL(),
|
||||
// $FlowFixMe[extra-arg] Add correct typing for `console.timeStamp`
|
||||
start,
|
||||
undefined,
|
||||
PERFORMANCE_TRACK_NAME,
|
||||
|
||||
@@ -10,21 +10,21 @@
|
||||
|
||||
import typeof {enable} from 'promise/setimmediate/rejection-tracking';
|
||||
|
||||
import ExceptionsManager from './Core/ExceptionsManager';
|
||||
import LogBox from './LogBox/LogBox';
|
||||
|
||||
let rejectionTrackingOptions: $NonMaybeType<Parameters<enable>[0]> = {
|
||||
allRejections: true,
|
||||
onUnhandled: (id, rejection) => {
|
||||
onUnhandled: (id, rejection = {}) => {
|
||||
let message: string;
|
||||
let stack: ?string;
|
||||
|
||||
if (rejection === undefined) {
|
||||
message = '';
|
||||
} else if (
|
||||
// $FlowFixMe[method-unbinding] added when improving typing for this parameters
|
||||
Object.prototype.toString.call(rejection) === '[object Error]'
|
||||
) {
|
||||
// $FlowFixMe[method-unbinding] added when improving typing for this parameters
|
||||
const stringValue = Object.prototype.toString.call(rejection);
|
||||
if (stringValue === '[object Error]') {
|
||||
// $FlowFixMe[method-unbinding] added when improving typing for this parameters
|
||||
message = Error.prototype.toString.call(rejection);
|
||||
const error: Error = (rejection: $FlowFixMe);
|
||||
stack = error.stack;
|
||||
} else {
|
||||
try {
|
||||
message = require('pretty-format').format(rejection);
|
||||
@@ -34,23 +34,37 @@ let rejectionTrackingOptions: $NonMaybeType<Parameters<enable>[0]> = {
|
||||
? rejection
|
||||
: JSON.stringify((rejection: $FlowFixMe));
|
||||
}
|
||||
// It could although this object is not a standard error, it still has stack information to unwind
|
||||
// $FlowFixMe ignore types just check if stack is there
|
||||
if (rejection?.stack && typeof rejection.stack === 'string') {
|
||||
stack = rejection.stack;
|
||||
}
|
||||
}
|
||||
|
||||
ExceptionsManager.handleException(
|
||||
new Error(
|
||||
`Uncaught (in promise, id: ${id})${message ? `: "${message}"` : ''}`,
|
||||
{
|
||||
cause: rejection,
|
||||
const warning = `Possible unhandled promise rejection (id: ${id}):\n${
|
||||
message ?? ''
|
||||
}`;
|
||||
if (__DEV__) {
|
||||
LogBox.addLog({
|
||||
level: 'warn',
|
||||
message: {
|
||||
content: warning,
|
||||
substitutions: [],
|
||||
},
|
||||
),
|
||||
false /* isFatal */,
|
||||
);
|
||||
componentStack: [],
|
||||
componentStackType: null,
|
||||
stack,
|
||||
category: 'possible_unhandled_promise_rejection',
|
||||
});
|
||||
} else {
|
||||
console.warn(warning);
|
||||
}
|
||||
},
|
||||
onHandled: id => {
|
||||
const warning =
|
||||
`Promise rejection handled (id: ${id})\n` +
|
||||
'This means you can ignore any previous messages of the form ' +
|
||||
`"Uncaught (in promise, id: ${id})"`;
|
||||
`"Possible unhandled promise rejection (id: ${id}):"`;
|
||||
console.warn(warning);
|
||||
},
|
||||
};
|
||||
|
||||
+4
-48
@@ -112,11 +112,6 @@ RCTSendScrollEventForNativeAnimations_DEPRECATED(UIScrollView *scrollView, NSInt
|
||||
__weak UIView *_firstVisibleView;
|
||||
|
||||
CGFloat _endDraggingSensitivityMultiplier;
|
||||
|
||||
// A flag indicating that accessibility API is used.
|
||||
// It is not restored to the default value in prepareForRecycle.
|
||||
// Once an accessibility API is used, view culling will be disabled for the entire session.
|
||||
BOOL _isAccessibilityAPIUsed;
|
||||
}
|
||||
|
||||
+ (RCTScrollViewComponentView *_Nullable)findScrollViewComponentViewForView:(UIView *)view
|
||||
@@ -139,7 +134,6 @@ RCTSendScrollEventForNativeAnimations_DEPRECATED(UIScrollView *scrollView, NSInt
|
||||
_isUserTriggeredScrolling = NO;
|
||||
_shouldUpdateContentInsetAdjustmentBehavior = YES;
|
||||
_automaticallyAdjustKeyboardInsets = NO;
|
||||
_isAccessibilityAPIUsed = NO;
|
||||
[self addSubview:_scrollView];
|
||||
|
||||
_containerView = [[UIView alloc] initWithFrame:CGRectZero];
|
||||
@@ -599,38 +593,6 @@ static inline UIViewAnimationOptions animationOptionsWithCurve(UIViewAnimationCu
|
||||
return metrics;
|
||||
}
|
||||
|
||||
/**
|
||||
* When use of accessibility APIs is detected, view culling is disabled to make accessibility work correctly.
|
||||
*/
|
||||
- (void)_disableViewCullingIfNecessary
|
||||
{
|
||||
if (!_isAccessibilityAPIUsed) {
|
||||
_isAccessibilityAPIUsed = YES;
|
||||
[self _updateStateWithContentOffset];
|
||||
}
|
||||
}
|
||||
|
||||
- (NSInteger)accessibilityElementCount
|
||||
{
|
||||
// From empirical testing, method `accessibilityElementCount` is called lazily only
|
||||
// when accessibility is used.
|
||||
// Why we don't use UIAccessibilitySwitchControlStatusDidChangeNotification and
|
||||
// UIAccessibilityVoiceOverStatusDidChangeNotification? The notifications are not called when using Accessibility
|
||||
// Inspector. We anticipate developers will want to debug accessbility with Accessibility Inspector and don't want to
|
||||
// break that developer workflow with view culling. Therefore, we are using API use detection to disable view culling
|
||||
// instead of the notifications.
|
||||
[self _disableViewCullingIfNecessary];
|
||||
return [super accessibilityElementCount];
|
||||
}
|
||||
|
||||
- (NSArray<id<UIFocusItem>> *)focusItemsInRect:(CGRect)rect
|
||||
{
|
||||
// From empirical testing, method `focusItemsInRect:` is called lazily only
|
||||
// when keyboard navigation is used.
|
||||
[self _disableViewCullingIfNecessary];
|
||||
return [super focusItemsInRect:rect];
|
||||
}
|
||||
|
||||
- (void)_updateStateWithContentOffset
|
||||
{
|
||||
if (!_state) {
|
||||
@@ -638,23 +600,17 @@ static inline UIViewAnimationOptions animationOptionsWithCurve(UIViewAnimationCu
|
||||
}
|
||||
|
||||
auto contentOffset = RCTPointFromCGPoint(_scrollView.contentOffset);
|
||||
BOOL isAccessibilityAPIUsed = _isAccessibilityAPIUsed;
|
||||
_state->updateState(
|
||||
[contentOffset, isAccessibilityAPIUsed](
|
||||
[contentOffset](
|
||||
const ScrollViewShadowNode::ConcreteState::Data &oldData) -> ScrollViewShadowNode::ConcreteState::SharedData {
|
||||
if (oldData.contentOffset == contentOffset && oldData.disableViewCulling == isAccessibilityAPIUsed) {
|
||||
// avoid doing a state update if content offset and use of accessibility didn't change.
|
||||
if (oldData.contentOffset == contentOffset) {
|
||||
// avoid doing a state update if content offset didn't change.
|
||||
return nullptr;
|
||||
}
|
||||
auto newData = oldData;
|
||||
newData.contentOffset = contentOffset;
|
||||
newData.disableViewCulling =
|
||||
UIAccessibilityIsVoiceOverRunning() || UIAccessibilityIsSwitchControlRunning() || isAccessibilityAPIUsed;
|
||||
return std::make_shared<const ScrollViewShadowNode::ConcreteState::Data>(newData);
|
||||
},
|
||||
ReactNativeFeatureFlags::enableImmediateUpdateModeForContentOffsetChanges()
|
||||
? EventQueue::UpdateMode::unstable_Immediate
|
||||
: EventQueue::UpdateMode::Asynchronous);
|
||||
});
|
||||
}
|
||||
|
||||
- (void)prepareForRecycle
|
||||
|
||||
+5
@@ -9,6 +9,7 @@
|
||||
#import "RCTParagraphComponentAccessibilityProvider.h"
|
||||
|
||||
#import <MobileCoreServices/UTCoreTypes.h>
|
||||
#import <React/RCTViewAccessibilityElement.h>
|
||||
#import <react/renderer/components/text/ParagraphComponentDescriptor.h>
|
||||
#import <react/renderer/components/text/ParagraphProps.h>
|
||||
#import <react/renderer/components/text/ParagraphState.h>
|
||||
@@ -226,6 +227,10 @@ using namespace facebook::react;
|
||||
for (NSObject *element in elements) {
|
||||
if ([element isKindOfClass:[UIView class]] && [cooptingCandidates containsObject:((UIView *)element)]) {
|
||||
return YES;
|
||||
} else if (
|
||||
[element isKindOfClass:[RCTViewAccessibilityElement class]] &&
|
||||
[cooptingCandidates containsObject:((RCTViewAccessibilityElement *)element).view]) {
|
||||
return YES;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* 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 "RCTViewComponentView.h"
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
/*
|
||||
* A UIAcccessibilityElement representing a RCTViewComponentView from an
|
||||
* accessibility standpoint. This enables RCTViewComponentView's to reference
|
||||
* themselves in `accessibilityElements` without actually being an accessibility
|
||||
* element. If it were, then iOS would not call into `accessibilityElements`.
|
||||
*/
|
||||
@interface RCTViewAccessibilityElement : UIAccessibilityElement
|
||||
|
||||
@property (readonly) RCTViewComponentView *view;
|
||||
|
||||
- (instancetype)initWithView:(RCTViewComponentView *)view;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
+83
@@ -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.
|
||||
*/
|
||||
|
||||
#import "RCTViewAccessibilityElement.h"
|
||||
|
||||
@implementation RCTViewAccessibilityElement
|
||||
|
||||
- (instancetype)initWithView:(RCTViewComponentView *)view
|
||||
{
|
||||
if (self = [super initWithAccessibilityContainer:view]) {
|
||||
_view = view;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (CGRect)accessibilityFrame
|
||||
{
|
||||
return UIAccessibilityConvertFrameToScreenCoordinates(_view.bounds, _view);
|
||||
}
|
||||
|
||||
#pragma mark - Forwarding to _view
|
||||
|
||||
- (NSString *)accessibilityLabel
|
||||
{
|
||||
return _view.accessibilityLabel;
|
||||
}
|
||||
|
||||
- (NSString *)accessibilityValue
|
||||
{
|
||||
return _view.accessibilityValue;
|
||||
}
|
||||
|
||||
- (UIAccessibilityTraits)accessibilityTraits
|
||||
{
|
||||
return _view.accessibilityTraits;
|
||||
}
|
||||
|
||||
- (NSString *)accessibilityHint
|
||||
{
|
||||
return _view.accessibilityHint;
|
||||
}
|
||||
|
||||
- (BOOL)accessibilityIgnoresInvertColors
|
||||
{
|
||||
return _view.accessibilityIgnoresInvertColors;
|
||||
}
|
||||
|
||||
- (BOOL)shouldGroupAccessibilityChildren
|
||||
{
|
||||
return _view.shouldGroupAccessibilityChildren;
|
||||
}
|
||||
|
||||
- (NSArray<UIAccessibilityCustomAction *> *)accessibilityCustomActions
|
||||
{
|
||||
return _view.accessibilityCustomActions;
|
||||
}
|
||||
|
||||
- (NSString *)accessibilityLanguage
|
||||
{
|
||||
return _view.accessibilityLanguage;
|
||||
}
|
||||
|
||||
- (BOOL)accessibilityViewIsModal
|
||||
{
|
||||
return _view.accessibilityViewIsModal;
|
||||
}
|
||||
|
||||
- (BOOL)accessibilityElementsHidden
|
||||
{
|
||||
return _view.accessibilityElementsHidden;
|
||||
}
|
||||
|
||||
- (BOOL)accessibilityRespondsToUserInteraction
|
||||
{
|
||||
return _view.accessibilityRespondsToUserInteraction;
|
||||
}
|
||||
|
||||
@end
|
||||
+35
-22
@@ -6,6 +6,7 @@
|
||||
*/
|
||||
|
||||
#import "RCTViewComponentView.h"
|
||||
#import "RCTViewAccessibilityElement.h"
|
||||
|
||||
#import <CoreGraphics/CoreGraphics.h>
|
||||
#import <QuartzCore/QuartzCore.h>
|
||||
@@ -50,6 +51,8 @@ const CGFloat BACKGROUND_COLOR_ZPOSITION = -1024.0f;
|
||||
UIView *_containerView;
|
||||
BOOL _useCustomContainerView;
|
||||
NSMutableSet<NSString *> *_accessibilityOrderNativeIDs;
|
||||
NSMutableArray<NSObject *> *_accessibilityElements;
|
||||
RCTViewAccessibilityElement *_axElementDescribingSelf;
|
||||
}
|
||||
|
||||
#ifdef RCT_DYNAMIC_FRAMEWORKS
|
||||
@@ -402,11 +405,7 @@ const CGFloat BACKGROUND_COLOR_ZPOSITION = -1024.0f;
|
||||
[_accessibilityOrderNativeIDs addObject:RCTNSStringFromString(childId)];
|
||||
}
|
||||
|
||||
// If we are prop updating and have children we can go ahead and assign this prop.
|
||||
// Otherwise, we might not have children attached yet and need to wait before then.
|
||||
if (self.currentContainerView.subviews.count > 0) {
|
||||
[self updateAccessibilityElements];
|
||||
}
|
||||
_accessibilityElements = [NSMutableArray new];
|
||||
}
|
||||
|
||||
// `accessibilityTraits`
|
||||
@@ -618,6 +617,7 @@ const CGFloat BACKGROUND_COLOR_ZPOSITION = -1024.0f;
|
||||
_isJSResponder = NO;
|
||||
_removeClippedSubviews = NO;
|
||||
_reactSubviews = [NSMutableArray new];
|
||||
_accessibilityElements = [NSMutableArray new];
|
||||
}
|
||||
|
||||
- (void)setPropKeysManagedByAnimated_DO_NOT_USE_THIS_IS_BROKEN:(NSSet<NSString *> *_Nullable)props
|
||||
@@ -1149,37 +1149,43 @@ static RCTBorderStyle RCTBorderStyleFromOutlineStyle(OutlineStyle outlineStyle)
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)didMoveToSuperview
|
||||
- (NSArray<NSObject *> *)accessibilityElements
|
||||
{
|
||||
// At this point we are guaranteed to have subviews, if we are going to have them
|
||||
if (ReactNativeFeatureFlags::enableAccessibilityOrder()) {
|
||||
[self updateAccessibilityElements];
|
||||
if ([_accessibilityOrderNativeIDs count] <= 0) {
|
||||
return super.accessibilityElements;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)updateAccessibilityElements
|
||||
{
|
||||
if ([_accessibilityOrderNativeIDs count] == 0) {
|
||||
self.accessibilityElements = nil;
|
||||
return;
|
||||
// TODO: Currently this ignores changes to descendant nativeID's. While that should rarely, if ever happen, it's an
|
||||
// edge case we should address. Currently this fixes some app deaths so landing this without addressing that edge case
|
||||
// for now.
|
||||
if ([_accessibilityElements count] > 0) {
|
||||
return _accessibilityElements;
|
||||
}
|
||||
|
||||
NSMutableDictionary<NSString *, UIView *> *nativeIdToView = [NSMutableDictionary new];
|
||||
|
||||
[RCTViewComponentView collectAccessibilityElements:self
|
||||
intoDictionary:nativeIdToView
|
||||
nativeIds:_accessibilityOrderNativeIDs];
|
||||
|
||||
NSMutableArray *accessibilityElements = [NSMutableArray new];
|
||||
for (const auto &childId : _props->accessibilityOrder) {
|
||||
for (auto childId : _props->accessibilityOrder) {
|
||||
NSString *nsStringChildId = RCTNSStringFromString(childId);
|
||||
|
||||
UIView *viewWithMatchingNativeId = [nativeIdToView objectForKey:nsStringChildId];
|
||||
if (viewWithMatchingNativeId != nil) {
|
||||
[accessibilityElements addObject:viewWithMatchingNativeId];
|
||||
// Special case to allow for self-referencing with accessibilityOrder
|
||||
if ([nsStringChildId isEqualToString:self.nativeId]) {
|
||||
if (!_axElementDescribingSelf) {
|
||||
_axElementDescribingSelf = [[RCTViewAccessibilityElement alloc] initWithView:self];
|
||||
}
|
||||
_axElementDescribingSelf.isAccessibilityElement = [super isAccessibilityElement];
|
||||
[_accessibilityElements addObject:_axElementDescribingSelf];
|
||||
} else {
|
||||
UIView *viewWithMatchingNativeId = [nativeIdToView objectForKey:nsStringChildId];
|
||||
if (viewWithMatchingNativeId) {
|
||||
[_accessibilityElements addObject:viewWithMatchingNativeId];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
self.accessibilityElements = accessibilityElements;
|
||||
return _accessibilityElements;
|
||||
}
|
||||
|
||||
+ (void)collectAccessibilityElements:(UIView *)view
|
||||
@@ -1246,6 +1252,13 @@ static NSString *RCTRecursiveAccessibilityLabel(UIView *view)
|
||||
return self.contentView.isAccessibilityElement;
|
||||
}
|
||||
|
||||
// If we reference ourselves in accessibilityOrder then we will make a
|
||||
// UIAccessibilityElement object to represent ourselves since returning YES
|
||||
// here would mean iOS would not call into accessibilityElements
|
||||
if ([_accessibilityOrderNativeIDs containsObject:self.nativeId]) {
|
||||
return NO;
|
||||
}
|
||||
|
||||
return [super isAccessibilityElement];
|
||||
}
|
||||
|
||||
|
||||
@@ -31,8 +31,8 @@ public abstract class com/facebook/react/HeadlessJsTaskService : android/app/Ser
|
||||
public fun <init> ()V
|
||||
public static final fun acquireWakeLockNow (Landroid/content/Context;)V
|
||||
protected final fun getReactContext ()Lcom/facebook/react/bridge/ReactContext;
|
||||
protected fun getReactHost ()Lcom/facebook/react/ReactHost;
|
||||
protected fun getReactNativeHost ()Lcom/facebook/react/ReactNativeHost;
|
||||
protected final fun getReactHost ()Lcom/facebook/react/ReactHost;
|
||||
protected final fun getReactNativeHost ()Lcom/facebook/react/ReactNativeHost;
|
||||
protected fun getTaskConfig (Landroid/content/Intent;)Lcom/facebook/react/jstasks/HeadlessJsTaskConfig;
|
||||
public fun onBind (Landroid/content/Intent;)Landroid/os/IBinder;
|
||||
public fun onDestroy ()V
|
||||
|
||||
@@ -621,7 +621,6 @@ dependencies {
|
||||
api(libs.androidx.autofill)
|
||||
api(libs.androidx.swiperefreshlayout)
|
||||
api(libs.androidx.tracing)
|
||||
api(libs.androidx.window)
|
||||
|
||||
api(libs.fbjni)
|
||||
api(libs.fresco)
|
||||
|
||||
+2
-2
@@ -113,7 +113,7 @@ public abstract class HeadlessJsTaskService : Service(), HeadlessJsTaskEventList
|
||||
* somewhere.
|
||||
*/
|
||||
@Suppress("DEPRECATION")
|
||||
protected open val reactNativeHost: ReactNativeHost
|
||||
protected val reactNativeHost: ReactNativeHost
|
||||
get() = (application as ReactApplication).reactNativeHost
|
||||
|
||||
/**
|
||||
@@ -121,7 +121,7 @@ public abstract class HeadlessJsTaskService : Service(), HeadlessJsTaskEventList
|
||||
* [ReactApplication] and calls [ReactApplication.reactHost]. This method assumes it is called in
|
||||
* new architecture and returns null if not.
|
||||
*/
|
||||
protected open val reactHost: ReactHost?
|
||||
protected val reactHost: ReactHost?
|
||||
get() = (application as ReactApplication).reactHost
|
||||
|
||||
protected val reactContext: ReactContext?
|
||||
|
||||
+2
-6
@@ -135,10 +135,6 @@ public class ReactRootView extends FrameLayout implements RootView, ReactRoot {
|
||||
private void init() {
|
||||
setRootViewTag(ReactRootViewTagGenerator.getNextRootViewTag());
|
||||
setClipChildren(false);
|
||||
|
||||
if (ReactNativeFeatureFlags.enableFontScaleChangesUpdatingLayout()) {
|
||||
DisplayMetricsHolder.initDisplayMetrics(getContext().getApplicationContext());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -869,7 +865,7 @@ public class ReactRootView extends FrameLayout implements RootView, ReactRoot {
|
||||
private int mDeviceRotation = 0;
|
||||
|
||||
/* package */ CustomGlobalLayoutListener() {
|
||||
DisplayMetricsHolder.initDisplayMetricsIfNotInitialized(getContext());
|
||||
DisplayMetricsHolder.initDisplayMetricsIfNotInitialized(getContext().getApplicationContext());
|
||||
mVisibleViewArea = new Rect();
|
||||
mMinKeyboardHeightDetected = (int) PixelUtil.toPixelFromDIP(60);
|
||||
}
|
||||
@@ -992,7 +988,7 @@ public class ReactRootView extends FrameLayout implements RootView, ReactRoot {
|
||||
return;
|
||||
}
|
||||
mDeviceRotation = rotation;
|
||||
DisplayMetricsHolder.initDisplayMetrics(getContext());
|
||||
DisplayMetricsHolder.initDisplayMetrics(getContext().getApplicationContext());
|
||||
emitOrientationChanged(rotation);
|
||||
}
|
||||
|
||||
|
||||
+1
-9
@@ -8,7 +8,6 @@
|
||||
package com.facebook.react.bridge
|
||||
|
||||
import com.facebook.proguard.annotations.DoNotStrip
|
||||
import com.facebook.react.internal.featureflags.ReactNativeFeatureFlags
|
||||
import java.util.ArrayList
|
||||
import java.util.Arrays
|
||||
import kotlin.jvm.JvmStatic
|
||||
@@ -66,16 +65,9 @@ public open class ReadableNativeArray protected constructor() : NativeArray(), R
|
||||
if (other !is ReadableNativeArray) {
|
||||
return false
|
||||
}
|
||||
|
||||
return if (ReactNativeFeatureFlags.useNativeEqualsInNativeReadableArrayAndroid()) {
|
||||
nativeEquals(other)
|
||||
} else {
|
||||
localArray.contentDeepEquals(other.localArray)
|
||||
}
|
||||
return localArray.contentDeepEquals(other.localArray)
|
||||
}
|
||||
|
||||
private external fun nativeEquals(other: ReadableNativeArray): Boolean
|
||||
|
||||
override fun toArrayList(): ArrayList<Any?> {
|
||||
val arrayList = ArrayList<Any?>()
|
||||
repeat(size()) { i ->
|
||||
|
||||
+1
-31
@@ -4,7 +4,7 @@
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @generated SignedSource<<a90efac589511beb130c499e51150de8>>
|
||||
* @generated SignedSource<<2d4b6e579aaa2b8392fa65d7f86d0351>>
|
||||
*/
|
||||
|
||||
/**
|
||||
@@ -162,12 +162,6 @@ public object ReactNativeFeatureFlags {
|
||||
@JvmStatic
|
||||
public fun enableIOSViewClipToPaddingBox(): Boolean = accessor.enableIOSViewClipToPaddingBox()
|
||||
|
||||
/**
|
||||
* Dispatches state updates for content offset changes synchronously on the main thread.
|
||||
*/
|
||||
@JvmStatic
|
||||
public fun enableImmediateUpdateModeForContentOffsetChanges(): Boolean = accessor.enableImmediateUpdateModeForContentOffsetChanges()
|
||||
|
||||
/**
|
||||
* This is to fix the issue with interop view manager where component descriptor lookup is causing ViewManager to preload.
|
||||
*/
|
||||
@@ -306,24 +300,12 @@ public object ReactNativeFeatureFlags {
|
||||
@JvmStatic
|
||||
public fun preparedTextCacheSize(): Double = accessor.preparedTextCacheSize()
|
||||
|
||||
/**
|
||||
* Enables a new mechanism in ShadowTree to prevent problems caused by multiple threads trying to commit concurrently. If a thread tries to commit a few times unsuccessfully, it will acquire a lock and try again.
|
||||
*/
|
||||
@JvmStatic
|
||||
public fun preventShadowTreeCommitExhaustionWithLocking(): Boolean = accessor.preventShadowTreeCommitExhaustionWithLocking()
|
||||
|
||||
/**
|
||||
* Releases the cached image data when it is consumed by the observers.
|
||||
*/
|
||||
@JvmStatic
|
||||
public fun releaseImageDataWhenConsumed(): Boolean = accessor.releaseImageDataWhenConsumed()
|
||||
|
||||
/**
|
||||
* Skip activity identity assertion in ReactHostImpl::onHostPause()
|
||||
*/
|
||||
@JvmStatic
|
||||
public fun skipActivityIdentityAssertionOnHostPause(): Boolean = accessor.skipActivityIdentityAssertionOnHostPause()
|
||||
|
||||
/**
|
||||
* Enables storing js caller stack when creating promise in native module. This is useful in case of Promise rejection and tracing the cause.
|
||||
*/
|
||||
@@ -348,18 +330,6 @@ public object ReactNativeFeatureFlags {
|
||||
@JvmStatic
|
||||
public fun useFabricInterop(): Boolean = accessor.useFabricInterop()
|
||||
|
||||
/**
|
||||
* Use a native implementation of equals in NativeReadableArray.
|
||||
*/
|
||||
@JvmStatic
|
||||
public fun useNativeEqualsInNativeReadableArrayAndroid(): Boolean = accessor.useNativeEqualsInNativeReadableArrayAndroid()
|
||||
|
||||
/**
|
||||
* Use a native implementation of TransformHelper
|
||||
*/
|
||||
@JvmStatic
|
||||
public fun useNativeTransformHelperAndroid(): Boolean = accessor.useNativeTransformHelperAndroid()
|
||||
|
||||
/**
|
||||
* When enabled, the native view configs are used in bridgeless mode.
|
||||
*/
|
||||
|
||||
+1
-51
@@ -4,7 +4,7 @@
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @generated SignedSource<<b32f66fb09971e786dd1380bbf417720>>
|
||||
* @generated SignedSource<<7e07bb5556c0935dd1dd7be433a32065>>
|
||||
*/
|
||||
|
||||
/**
|
||||
@@ -42,7 +42,6 @@ internal class ReactNativeFeatureFlagsCxxAccessor : ReactNativeFeatureFlagsAcces
|
||||
private var enableFontScaleChangesUpdatingLayoutCache: Boolean? = null
|
||||
private var enableIOSTextBaselineOffsetPerLineCache: Boolean? = null
|
||||
private var enableIOSViewClipToPaddingBoxCache: Boolean? = null
|
||||
private var enableImmediateUpdateModeForContentOffsetChangesCache: Boolean? = null
|
||||
private var enableInteropViewManagerClassLookUpOptimizationIOSCache: Boolean? = null
|
||||
private var enableLayoutAnimationsOnAndroidCache: Boolean? = null
|
||||
private var enableLayoutAnimationsOnIOSCache: Boolean? = null
|
||||
@@ -66,15 +65,11 @@ internal class ReactNativeFeatureFlagsCxxAccessor : ReactNativeFeatureFlagsAcces
|
||||
private var fuseboxNetworkInspectionEnabledCache: Boolean? = null
|
||||
private var hideOffscreenVirtualViewsOnIOSCache: Boolean? = null
|
||||
private var preparedTextCacheSizeCache: Double? = null
|
||||
private var preventShadowTreeCommitExhaustionWithLockingCache: Boolean? = null
|
||||
private var releaseImageDataWhenConsumedCache: Boolean? = null
|
||||
private var skipActivityIdentityAssertionOnHostPauseCache: Boolean? = null
|
||||
private var traceTurboModulePromiseRejectionsOnAndroidCache: Boolean? = null
|
||||
private var updateRuntimeShadowNodeReferencesOnCommitCache: Boolean? = null
|
||||
private var useAlwaysAvailableJSErrorHandlingCache: Boolean? = null
|
||||
private var useFabricInteropCache: Boolean? = null
|
||||
private var useNativeEqualsInNativeReadableArrayAndroidCache: Boolean? = null
|
||||
private var useNativeTransformHelperAndroidCache: Boolean? = null
|
||||
private var useNativeViewConfigsInBridgelessModeCache: Boolean? = null
|
||||
private var useOptimizedEventBatchingOnAndroidCache: Boolean? = null
|
||||
private var useRawPropsJsiValueCache: Boolean? = null
|
||||
@@ -281,15 +276,6 @@ internal class ReactNativeFeatureFlagsCxxAccessor : ReactNativeFeatureFlagsAcces
|
||||
return cached
|
||||
}
|
||||
|
||||
override fun enableImmediateUpdateModeForContentOffsetChanges(): Boolean {
|
||||
var cached = enableImmediateUpdateModeForContentOffsetChangesCache
|
||||
if (cached == null) {
|
||||
cached = ReactNativeFeatureFlagsCxxInterop.enableImmediateUpdateModeForContentOffsetChanges()
|
||||
enableImmediateUpdateModeForContentOffsetChangesCache = cached
|
||||
}
|
||||
return cached
|
||||
}
|
||||
|
||||
override fun enableInteropViewManagerClassLookUpOptimizationIOS(): Boolean {
|
||||
var cached = enableInteropViewManagerClassLookUpOptimizationIOSCache
|
||||
if (cached == null) {
|
||||
@@ -497,15 +483,6 @@ internal class ReactNativeFeatureFlagsCxxAccessor : ReactNativeFeatureFlagsAcces
|
||||
return cached
|
||||
}
|
||||
|
||||
override fun preventShadowTreeCommitExhaustionWithLocking(): Boolean {
|
||||
var cached = preventShadowTreeCommitExhaustionWithLockingCache
|
||||
if (cached == null) {
|
||||
cached = ReactNativeFeatureFlagsCxxInterop.preventShadowTreeCommitExhaustionWithLocking()
|
||||
preventShadowTreeCommitExhaustionWithLockingCache = cached
|
||||
}
|
||||
return cached
|
||||
}
|
||||
|
||||
override fun releaseImageDataWhenConsumed(): Boolean {
|
||||
var cached = releaseImageDataWhenConsumedCache
|
||||
if (cached == null) {
|
||||
@@ -515,15 +492,6 @@ internal class ReactNativeFeatureFlagsCxxAccessor : ReactNativeFeatureFlagsAcces
|
||||
return cached
|
||||
}
|
||||
|
||||
override fun skipActivityIdentityAssertionOnHostPause(): Boolean {
|
||||
var cached = skipActivityIdentityAssertionOnHostPauseCache
|
||||
if (cached == null) {
|
||||
cached = ReactNativeFeatureFlagsCxxInterop.skipActivityIdentityAssertionOnHostPause()
|
||||
skipActivityIdentityAssertionOnHostPauseCache = cached
|
||||
}
|
||||
return cached
|
||||
}
|
||||
|
||||
override fun traceTurboModulePromiseRejectionsOnAndroid(): Boolean {
|
||||
var cached = traceTurboModulePromiseRejectionsOnAndroidCache
|
||||
if (cached == null) {
|
||||
@@ -560,24 +528,6 @@ internal class ReactNativeFeatureFlagsCxxAccessor : ReactNativeFeatureFlagsAcces
|
||||
return cached
|
||||
}
|
||||
|
||||
override fun useNativeEqualsInNativeReadableArrayAndroid(): Boolean {
|
||||
var cached = useNativeEqualsInNativeReadableArrayAndroidCache
|
||||
if (cached == null) {
|
||||
cached = ReactNativeFeatureFlagsCxxInterop.useNativeEqualsInNativeReadableArrayAndroid()
|
||||
useNativeEqualsInNativeReadableArrayAndroidCache = cached
|
||||
}
|
||||
return cached
|
||||
}
|
||||
|
||||
override fun useNativeTransformHelperAndroid(): Boolean {
|
||||
var cached = useNativeTransformHelperAndroidCache
|
||||
if (cached == null) {
|
||||
cached = ReactNativeFeatureFlagsCxxInterop.useNativeTransformHelperAndroid()
|
||||
useNativeTransformHelperAndroidCache = cached
|
||||
}
|
||||
return cached
|
||||
}
|
||||
|
||||
override fun useNativeViewConfigsInBridgelessMode(): Boolean {
|
||||
var cached = useNativeViewConfigsInBridgelessModeCache
|
||||
if (cached == null) {
|
||||
|
||||
+1
-11
@@ -4,7 +4,7 @@
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @generated SignedSource<<d1da48f826bc6a1793d1630cb89cb5c1>>
|
||||
* @generated SignedSource<<1cbcbe3a0563e6254d4e377be394f1ab>>
|
||||
*/
|
||||
|
||||
/**
|
||||
@@ -72,8 +72,6 @@ public object ReactNativeFeatureFlagsCxxInterop {
|
||||
|
||||
@DoNotStrip @JvmStatic public external fun enableIOSViewClipToPaddingBox(): Boolean
|
||||
|
||||
@DoNotStrip @JvmStatic public external fun enableImmediateUpdateModeForContentOffsetChanges(): Boolean
|
||||
|
||||
@DoNotStrip @JvmStatic public external fun enableInteropViewManagerClassLookUpOptimizationIOS(): Boolean
|
||||
|
||||
@DoNotStrip @JvmStatic public external fun enableLayoutAnimationsOnAndroid(): Boolean
|
||||
@@ -120,12 +118,8 @@ public object ReactNativeFeatureFlagsCxxInterop {
|
||||
|
||||
@DoNotStrip @JvmStatic public external fun preparedTextCacheSize(): Double
|
||||
|
||||
@DoNotStrip @JvmStatic public external fun preventShadowTreeCommitExhaustionWithLocking(): Boolean
|
||||
|
||||
@DoNotStrip @JvmStatic public external fun releaseImageDataWhenConsumed(): Boolean
|
||||
|
||||
@DoNotStrip @JvmStatic public external fun skipActivityIdentityAssertionOnHostPause(): Boolean
|
||||
|
||||
@DoNotStrip @JvmStatic public external fun traceTurboModulePromiseRejectionsOnAndroid(): Boolean
|
||||
|
||||
@DoNotStrip @JvmStatic public external fun updateRuntimeShadowNodeReferencesOnCommit(): Boolean
|
||||
@@ -134,10 +128,6 @@ public object ReactNativeFeatureFlagsCxxInterop {
|
||||
|
||||
@DoNotStrip @JvmStatic public external fun useFabricInterop(): Boolean
|
||||
|
||||
@DoNotStrip @JvmStatic public external fun useNativeEqualsInNativeReadableArrayAndroid(): Boolean
|
||||
|
||||
@DoNotStrip @JvmStatic public external fun useNativeTransformHelperAndroid(): Boolean
|
||||
|
||||
@DoNotStrip @JvmStatic public external fun useNativeViewConfigsInBridgelessMode(): Boolean
|
||||
|
||||
@DoNotStrip @JvmStatic public external fun useOptimizedEventBatchingOnAndroid(): Boolean
|
||||
|
||||
+2
-12
@@ -4,7 +4,7 @@
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @generated SignedSource<<c5ed8a904dcda7ade87527233b879b92>>
|
||||
* @generated SignedSource<<070a222658505c3ddc87911441499518>>
|
||||
*/
|
||||
|
||||
/**
|
||||
@@ -67,8 +67,6 @@ public open class ReactNativeFeatureFlagsDefaults : ReactNativeFeatureFlagsProvi
|
||||
|
||||
override fun enableIOSViewClipToPaddingBox(): Boolean = false
|
||||
|
||||
override fun enableImmediateUpdateModeForContentOffsetChanges(): Boolean = false
|
||||
|
||||
override fun enableInteropViewManagerClassLookUpOptimizationIOS(): Boolean = false
|
||||
|
||||
override fun enableLayoutAnimationsOnAndroid(): Boolean = false
|
||||
@@ -101,7 +99,7 @@ public open class ReactNativeFeatureFlagsDefaults : ReactNativeFeatureFlagsProvi
|
||||
|
||||
override fun enableVirtualViewDebugFeatures(): Boolean = false
|
||||
|
||||
override fun enableVirtualViewRenderState(): Boolean = true
|
||||
override fun enableVirtualViewRenderState(): Boolean = false
|
||||
|
||||
override fun enableVirtualViewWindowFocusDetection(): Boolean = false
|
||||
|
||||
@@ -115,12 +113,8 @@ public open class ReactNativeFeatureFlagsDefaults : ReactNativeFeatureFlagsProvi
|
||||
|
||||
override fun preparedTextCacheSize(): Double = 200.0
|
||||
|
||||
override fun preventShadowTreeCommitExhaustionWithLocking(): Boolean = false
|
||||
|
||||
override fun releaseImageDataWhenConsumed(): Boolean = false
|
||||
|
||||
override fun skipActivityIdentityAssertionOnHostPause(): Boolean = false
|
||||
|
||||
override fun traceTurboModulePromiseRejectionsOnAndroid(): Boolean = false
|
||||
|
||||
override fun updateRuntimeShadowNodeReferencesOnCommit(): Boolean = false
|
||||
@@ -129,10 +123,6 @@ public open class ReactNativeFeatureFlagsDefaults : ReactNativeFeatureFlagsProvi
|
||||
|
||||
override fun useFabricInterop(): Boolean = true
|
||||
|
||||
override fun useNativeEqualsInNativeReadableArrayAndroid(): Boolean = false
|
||||
|
||||
override fun useNativeTransformHelperAndroid(): Boolean = false
|
||||
|
||||
override fun useNativeViewConfigsInBridgelessMode(): Boolean = false
|
||||
|
||||
override fun useOptimizedEventBatchingOnAndroid(): Boolean = false
|
||||
|
||||
+1
-56
@@ -4,7 +4,7 @@
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @generated SignedSource<<23605f090bfbebe911caa9d3d834d3e8>>
|
||||
* @generated SignedSource<<872fdabc2969e8c8e77993d73a152a4b>>
|
||||
*/
|
||||
|
||||
/**
|
||||
@@ -46,7 +46,6 @@ internal class ReactNativeFeatureFlagsLocalAccessor : ReactNativeFeatureFlagsAcc
|
||||
private var enableFontScaleChangesUpdatingLayoutCache: Boolean? = null
|
||||
private var enableIOSTextBaselineOffsetPerLineCache: Boolean? = null
|
||||
private var enableIOSViewClipToPaddingBoxCache: Boolean? = null
|
||||
private var enableImmediateUpdateModeForContentOffsetChangesCache: Boolean? = null
|
||||
private var enableInteropViewManagerClassLookUpOptimizationIOSCache: Boolean? = null
|
||||
private var enableLayoutAnimationsOnAndroidCache: Boolean? = null
|
||||
private var enableLayoutAnimationsOnIOSCache: Boolean? = null
|
||||
@@ -70,15 +69,11 @@ internal class ReactNativeFeatureFlagsLocalAccessor : ReactNativeFeatureFlagsAcc
|
||||
private var fuseboxNetworkInspectionEnabledCache: Boolean? = null
|
||||
private var hideOffscreenVirtualViewsOnIOSCache: Boolean? = null
|
||||
private var preparedTextCacheSizeCache: Double? = null
|
||||
private var preventShadowTreeCommitExhaustionWithLockingCache: Boolean? = null
|
||||
private var releaseImageDataWhenConsumedCache: Boolean? = null
|
||||
private var skipActivityIdentityAssertionOnHostPauseCache: Boolean? = null
|
||||
private var traceTurboModulePromiseRejectionsOnAndroidCache: Boolean? = null
|
||||
private var updateRuntimeShadowNodeReferencesOnCommitCache: Boolean? = null
|
||||
private var useAlwaysAvailableJSErrorHandlingCache: Boolean? = null
|
||||
private var useFabricInteropCache: Boolean? = null
|
||||
private var useNativeEqualsInNativeReadableArrayAndroidCache: Boolean? = null
|
||||
private var useNativeTransformHelperAndroidCache: Boolean? = null
|
||||
private var useNativeViewConfigsInBridgelessModeCache: Boolean? = null
|
||||
private var useOptimizedEventBatchingOnAndroidCache: Boolean? = null
|
||||
private var useRawPropsJsiValueCache: Boolean? = null
|
||||
@@ -307,16 +302,6 @@ internal class ReactNativeFeatureFlagsLocalAccessor : ReactNativeFeatureFlagsAcc
|
||||
return cached
|
||||
}
|
||||
|
||||
override fun enableImmediateUpdateModeForContentOffsetChanges(): Boolean {
|
||||
var cached = enableImmediateUpdateModeForContentOffsetChangesCache
|
||||
if (cached == null) {
|
||||
cached = currentProvider.enableImmediateUpdateModeForContentOffsetChanges()
|
||||
accessedFeatureFlags.add("enableImmediateUpdateModeForContentOffsetChanges")
|
||||
enableImmediateUpdateModeForContentOffsetChangesCache = cached
|
||||
}
|
||||
return cached
|
||||
}
|
||||
|
||||
override fun enableInteropViewManagerClassLookUpOptimizationIOS(): Boolean {
|
||||
var cached = enableInteropViewManagerClassLookUpOptimizationIOSCache
|
||||
if (cached == null) {
|
||||
@@ -547,16 +532,6 @@ internal class ReactNativeFeatureFlagsLocalAccessor : ReactNativeFeatureFlagsAcc
|
||||
return cached
|
||||
}
|
||||
|
||||
override fun preventShadowTreeCommitExhaustionWithLocking(): Boolean {
|
||||
var cached = preventShadowTreeCommitExhaustionWithLockingCache
|
||||
if (cached == null) {
|
||||
cached = currentProvider.preventShadowTreeCommitExhaustionWithLocking()
|
||||
accessedFeatureFlags.add("preventShadowTreeCommitExhaustionWithLocking")
|
||||
preventShadowTreeCommitExhaustionWithLockingCache = cached
|
||||
}
|
||||
return cached
|
||||
}
|
||||
|
||||
override fun releaseImageDataWhenConsumed(): Boolean {
|
||||
var cached = releaseImageDataWhenConsumedCache
|
||||
if (cached == null) {
|
||||
@@ -567,16 +542,6 @@ internal class ReactNativeFeatureFlagsLocalAccessor : ReactNativeFeatureFlagsAcc
|
||||
return cached
|
||||
}
|
||||
|
||||
override fun skipActivityIdentityAssertionOnHostPause(): Boolean {
|
||||
var cached = skipActivityIdentityAssertionOnHostPauseCache
|
||||
if (cached == null) {
|
||||
cached = currentProvider.skipActivityIdentityAssertionOnHostPause()
|
||||
accessedFeatureFlags.add("skipActivityIdentityAssertionOnHostPause")
|
||||
skipActivityIdentityAssertionOnHostPauseCache = cached
|
||||
}
|
||||
return cached
|
||||
}
|
||||
|
||||
override fun traceTurboModulePromiseRejectionsOnAndroid(): Boolean {
|
||||
var cached = traceTurboModulePromiseRejectionsOnAndroidCache
|
||||
if (cached == null) {
|
||||
@@ -617,26 +582,6 @@ internal class ReactNativeFeatureFlagsLocalAccessor : ReactNativeFeatureFlagsAcc
|
||||
return cached
|
||||
}
|
||||
|
||||
override fun useNativeEqualsInNativeReadableArrayAndroid(): Boolean {
|
||||
var cached = useNativeEqualsInNativeReadableArrayAndroidCache
|
||||
if (cached == null) {
|
||||
cached = currentProvider.useNativeEqualsInNativeReadableArrayAndroid()
|
||||
accessedFeatureFlags.add("useNativeEqualsInNativeReadableArrayAndroid")
|
||||
useNativeEqualsInNativeReadableArrayAndroidCache = cached
|
||||
}
|
||||
return cached
|
||||
}
|
||||
|
||||
override fun useNativeTransformHelperAndroid(): Boolean {
|
||||
var cached = useNativeTransformHelperAndroidCache
|
||||
if (cached == null) {
|
||||
cached = currentProvider.useNativeTransformHelperAndroid()
|
||||
accessedFeatureFlags.add("useNativeTransformHelperAndroid")
|
||||
useNativeTransformHelperAndroidCache = cached
|
||||
}
|
||||
return cached
|
||||
}
|
||||
|
||||
override fun useNativeViewConfigsInBridgelessMode(): Boolean {
|
||||
var cached = useNativeViewConfigsInBridgelessModeCache
|
||||
if (cached == null) {
|
||||
|
||||
+1
-11
@@ -4,7 +4,7 @@
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @generated SignedSource<<780793412b76f101be1569d7a866c435>>
|
||||
* @generated SignedSource<<63bdcd9aeb09a55028595eecb42cdcae>>
|
||||
*/
|
||||
|
||||
/**
|
||||
@@ -67,8 +67,6 @@ public interface ReactNativeFeatureFlagsProvider {
|
||||
|
||||
@DoNotStrip public fun enableIOSViewClipToPaddingBox(): Boolean
|
||||
|
||||
@DoNotStrip public fun enableImmediateUpdateModeForContentOffsetChanges(): Boolean
|
||||
|
||||
@DoNotStrip public fun enableInteropViewManagerClassLookUpOptimizationIOS(): Boolean
|
||||
|
||||
@DoNotStrip public fun enableLayoutAnimationsOnAndroid(): Boolean
|
||||
@@ -115,12 +113,8 @@ public interface ReactNativeFeatureFlagsProvider {
|
||||
|
||||
@DoNotStrip public fun preparedTextCacheSize(): Double
|
||||
|
||||
@DoNotStrip public fun preventShadowTreeCommitExhaustionWithLocking(): Boolean
|
||||
|
||||
@DoNotStrip public fun releaseImageDataWhenConsumed(): Boolean
|
||||
|
||||
@DoNotStrip public fun skipActivityIdentityAssertionOnHostPause(): Boolean
|
||||
|
||||
@DoNotStrip public fun traceTurboModulePromiseRejectionsOnAndroid(): Boolean
|
||||
|
||||
@DoNotStrip public fun updateRuntimeShadowNodeReferencesOnCommit(): Boolean
|
||||
@@ -129,10 +123,6 @@ public interface ReactNativeFeatureFlagsProvider {
|
||||
|
||||
@DoNotStrip public fun useFabricInterop(): Boolean
|
||||
|
||||
@DoNotStrip public fun useNativeEqualsInNativeReadableArrayAndroid(): Boolean
|
||||
|
||||
@DoNotStrip public fun useNativeTransformHelperAndroid(): Boolean
|
||||
|
||||
@DoNotStrip public fun useNativeViewConfigsInBridgelessMode(): Boolean
|
||||
|
||||
@DoNotStrip public fun useOptimizedEventBatchingOnAndroid(): Boolean
|
||||
|
||||
+4
@@ -23,6 +23,10 @@ import com.facebook.react.common.build.ReactBuildConfig
|
||||
@SuppressLint("UseReactNativeNewArchitectureFeatureFlagDetector")
|
||||
public object ReactNativeNewArchitectureFeatureFlags {
|
||||
|
||||
@JvmStatic
|
||||
public fun isNewArchitectureStrictModeEnabled(): Boolean =
|
||||
ReactBuildConfig.UNSTABLE_ENABLE_MINIFY_LEGACY_ARCHITECTURE
|
||||
|
||||
@JvmStatic
|
||||
public fun enableBridgelessArchitecture(): Boolean {
|
||||
if (ReactBuildConfig.UNSTABLE_ENABLE_MINIFY_LEGACY_ARCHITECTURE) {
|
||||
|
||||
+5
-12
@@ -253,18 +253,11 @@ public class ReactHostImpl(
|
||||
|
||||
val currentActivity = this.currentActivity
|
||||
if (currentActivity != null) {
|
||||
val isSameActivity = activity === currentActivity
|
||||
if (!isSameActivity) {
|
||||
val currentActivityClass = currentActivity.javaClass.simpleName
|
||||
val activityClass = if (activity == null) "null" else activity.javaClass.simpleName
|
||||
val isNotSameActivityMessage =
|
||||
"Pausing an activity that is not the current activity, this is incorrect! Current activity: $currentActivityClass Paused activity: $activityClass"
|
||||
if (ReactNativeFeatureFlags.skipActivityIdentityAssertionOnHostPause()) {
|
||||
log(method, isNotSameActivityMessage)
|
||||
} else {
|
||||
Assertions.assertCondition(isSameActivity, isNotSameActivityMessage)
|
||||
}
|
||||
}
|
||||
val currentActivityClass = currentActivity.javaClass.simpleName
|
||||
val activityClass = if (activity == null) "null" else activity.javaClass.simpleName
|
||||
Assertions.assertCondition(
|
||||
activity === currentActivity,
|
||||
"Pausing an activity that is not the current activity, this is incorrect! Current activity: $currentActivityClass Paused activity: $activityClass")
|
||||
}
|
||||
|
||||
maybeEnableDevSupport(false)
|
||||
|
||||
+1
-15
@@ -13,10 +13,8 @@ import android.util.DisplayMetrics
|
||||
import android.view.WindowManager
|
||||
import androidx.core.view.ViewCompat
|
||||
import androidx.core.view.WindowInsetsCompat
|
||||
import androidx.window.layout.WindowMetricsCalculator
|
||||
import com.facebook.react.bridge.WritableMap
|
||||
import com.facebook.react.bridge.WritableNativeMap
|
||||
import com.facebook.react.views.view.isEdgeToEdgeFeatureFlagOn
|
||||
|
||||
/**
|
||||
* Holds an instance of the current DisplayMetrics so we don't have to thread it through all the
|
||||
@@ -64,19 +62,9 @@ public object DisplayMetricsHolder {
|
||||
@JvmStatic
|
||||
public fun initDisplayMetrics(context: Context) {
|
||||
val displayMetrics = context.resources.displayMetrics
|
||||
val windowDisplayMetrics = DisplayMetrics()
|
||||
windowDisplayMetrics = displayMetrics
|
||||
val screenDisplayMetrics = DisplayMetrics()
|
||||
|
||||
windowDisplayMetrics.setTo(displayMetrics)
|
||||
screenDisplayMetrics.setTo(displayMetrics)
|
||||
|
||||
if (isEdgeToEdgeFeatureFlagOn) {
|
||||
WindowMetricsCalculator.getOrCreate().computeCurrentWindowMetrics(context).let {
|
||||
windowDisplayMetrics.widthPixels = it.bounds.width()
|
||||
windowDisplayMetrics.heightPixels = it.bounds.height()
|
||||
}
|
||||
}
|
||||
|
||||
val wm = context.getSystemService(Context.WINDOW_SERVICE) as WindowManager
|
||||
// Get the real display metrics if we are using API level 17 or higher.
|
||||
// The real metrics include system decor elements (e.g. soft menu bar).
|
||||
@@ -84,8 +72,6 @@ public object DisplayMetricsHolder {
|
||||
// See:
|
||||
// http://developer.android.com/reference/android/view/Display.html#getRealMetrics(android.util.DisplayMetrics)
|
||||
@Suppress("DEPRECATION") wm.defaultDisplay.getRealMetrics(screenDisplayMetrics)
|
||||
|
||||
DisplayMetricsHolder.windowDisplayMetrics = windowDisplayMetrics
|
||||
DisplayMetricsHolder.screenDisplayMetrics = screenDisplayMetrics
|
||||
}
|
||||
|
||||
|
||||
+2
-2
@@ -19,7 +19,7 @@ import com.facebook.react.uimanager.PixelUtil.toDIPFromPixel
|
||||
import com.facebook.react.uimanager.events.Event
|
||||
|
||||
/** Event used to notify JS component about changes of its position or dimensions. */
|
||||
@LegacyArchitecture(logLevel = LegacyArchitectureLogLevel.WARNING)
|
||||
@LegacyArchitecture(logLevel = LegacyArchitectureLogLevel.ERROR)
|
||||
public class OnLayoutEvent private constructor() : Event<OnLayoutEvent>() {
|
||||
@VisibleForTesting internal var x: Int = 0
|
||||
@VisibleForTesting internal var y: Int = 0
|
||||
@@ -60,7 +60,7 @@ public class OnLayoutEvent private constructor() : Event<OnLayoutEvent>() {
|
||||
public companion object {
|
||||
init {
|
||||
LegacyArchitectureLogger.assertLegacyArchitecture(
|
||||
"OnLayoutEvent", LegacyArchitectureLogLevel.WARNING)
|
||||
"OnLayoutEvent", LegacyArchitectureLogLevel.ERROR)
|
||||
}
|
||||
|
||||
private val EVENTS_POOL: SynchronizedPool<OnLayoutEvent> = SynchronizedPool<OnLayoutEvent>(20)
|
||||
|
||||
-19
@@ -8,12 +8,10 @@
|
||||
package com.facebook.react.uimanager
|
||||
|
||||
import com.facebook.common.logging.FLog
|
||||
import com.facebook.react.bridge.NativeArray
|
||||
import com.facebook.react.bridge.ReadableArray
|
||||
import com.facebook.react.bridge.ReadableMap
|
||||
import com.facebook.react.bridge.ReadableType
|
||||
import com.facebook.react.common.ReactConstants
|
||||
import com.facebook.react.internal.featureflags.ReactNativeFeatureFlags
|
||||
|
||||
public object TransformHelper {
|
||||
|
||||
@@ -71,14 +69,6 @@ public object TransformHelper {
|
||||
transformOrigin: ReadableArray?,
|
||||
allowPercentageResolution: Boolean
|
||||
) {
|
||||
if (allowPercentageResolution &&
|
||||
ReactNativeFeatureFlags.useNativeTransformHelperAndroid() &&
|
||||
transforms is NativeArray &&
|
||||
transformOrigin is NativeArray?) {
|
||||
nativeProcessTransform(transforms, result, viewWidth, viewHeight, transformOrigin)
|
||||
return
|
||||
}
|
||||
|
||||
val helperMatrix = helperMatrix.get()!!
|
||||
MatrixMathHelper.resetIdentityMatrix(result)
|
||||
val offsets =
|
||||
@@ -230,13 +220,4 @@ public object TransformHelper {
|
||||
|
||||
return doubleArrayOf(newTranslateX, newTranslateY, newTranslateZ)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
private external fun nativeProcessTransform(
|
||||
transforms: NativeArray,
|
||||
result: DoubleArray,
|
||||
viewWidth: Float,
|
||||
viewHeight: Float,
|
||||
transformOrigin: NativeArray?
|
||||
)
|
||||
}
|
||||
|
||||
-6
@@ -377,9 +377,6 @@ public class ReactScrollView extends ScrollView
|
||||
}
|
||||
|
||||
ReactScrollViewHelper.emitLayoutEvent(this);
|
||||
if (mVirtualViewContainerState != null) {
|
||||
mVirtualViewContainerState.updateState();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -489,9 +486,6 @@ public class ReactScrollView extends ScrollView
|
||||
this,
|
||||
mOnScrollDispatchHelper.getXFlingVelocity(),
|
||||
mOnScrollDispatchHelper.getYFlingVelocity());
|
||||
if (mVirtualViewContainerState != null) {
|
||||
mVirtualViewContainerState.updateState();
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
Systrace.endSection(Systrace.TRACE_TAG_REACT);
|
||||
|
||||
+42
-27
@@ -11,7 +11,6 @@ import android.graphics.Rect
|
||||
import android.view.ViewGroup
|
||||
import com.facebook.common.logging.FLog
|
||||
import com.facebook.react.common.build.ReactBuildConfig
|
||||
import com.facebook.react.internal.featureflags.ReactNativeFeatureFlags
|
||||
import com.facebook.react.views.virtual.VirtualViewMode
|
||||
import java.util.*
|
||||
|
||||
@@ -46,19 +45,22 @@ private fun rectsOverlap(rect1: Rect, rect2: Rect): Boolean {
|
||||
return true
|
||||
}
|
||||
|
||||
internal class VirtualViewContainerState(private val scrollView: ViewGroup) {
|
||||
internal class VirtualViewContainerState(private val scrollView: ViewGroup) :
|
||||
ReactScrollViewHelper.ScrollListener {
|
||||
|
||||
private val prerenderRatio: Double = ReactNativeFeatureFlags.virtualViewPrerenderRatio()
|
||||
private val prerenderRatio: Int = 1
|
||||
private val virtualViews: MutableSet<VirtualView> = mutableSetOf()
|
||||
private val emptyRect: Rect = Rect()
|
||||
private val visibleRect: Rect = Rect()
|
||||
private val prerenderRect: Rect = Rect()
|
||||
|
||||
public fun onChange(virtualView: VirtualView) {
|
||||
if (virtualViews.add(virtualView)) {
|
||||
debugLog("add", { "virtualViewID=${virtualView.virtualViewID}" })
|
||||
} else {
|
||||
debugLog("update", { "virtualViewID=${virtualView.virtualViewID}" })
|
||||
init {
|
||||
ReactScrollViewHelper.addScrollListener(this)
|
||||
}
|
||||
|
||||
public fun add(virtualView: VirtualView) {
|
||||
assert(virtualViews.add(virtualView)) {
|
||||
"Attempting to add duplicate VirtualView: ${virtualView.virtualViewID}"
|
||||
}
|
||||
updateModes(virtualView)
|
||||
}
|
||||
@@ -67,13 +69,35 @@ internal class VirtualViewContainerState(private val scrollView: ViewGroup) {
|
||||
assert(virtualViews.remove(virtualView)) {
|
||||
"Attempting to remove non-existent VirtualView: ${virtualView.virtualViewID}"
|
||||
}
|
||||
debugLog("remove", { "virtualViewID=${virtualView.virtualViewID}" })
|
||||
}
|
||||
|
||||
// Called on ScrollView onLayout or onScroll
|
||||
public fun updateState() {
|
||||
debugLog("VirtualViewContainer.updateState")
|
||||
updateModes()
|
||||
// ReactScrollViewHelper.ScrollListener.onLayout
|
||||
// Emitted from ScrollView's onLayout
|
||||
override fun onLayout(scrollView: ViewGroup?) {
|
||||
// ReactScrollViewHelper is global
|
||||
if (this.scrollView == scrollView) {
|
||||
debugLog("ReactScrollViewHelper.onLayout")
|
||||
updateModes()
|
||||
}
|
||||
}
|
||||
|
||||
// ReactScrollViewHelper.ScrollListener.onScroll
|
||||
// Emitted from ScrollView's onLayout
|
||||
override fun onScroll(
|
||||
scrollView: ViewGroup?,
|
||||
scrollEventType: ScrollEventType?,
|
||||
xVelocity: Float,
|
||||
yVelocity: Float
|
||||
) {
|
||||
// ReactScrollViewHelper is global
|
||||
if (this.scrollView == scrollView) {
|
||||
debugLog("ReactScrollViewHelper.onScroll")
|
||||
updateModes()
|
||||
}
|
||||
}
|
||||
|
||||
public fun update(virtualView: VirtualView) {
|
||||
updateModes(virtualView)
|
||||
}
|
||||
|
||||
private fun updateModes(virtualView: VirtualView? = null) {
|
||||
@@ -86,26 +110,17 @@ internal class VirtualViewContainerState(private val scrollView: ViewGroup) {
|
||||
val virtualViewsIt = if (virtualView != null) listOf(virtualView) else virtualViews
|
||||
virtualViewsIt.forEach { vv ->
|
||||
val rect = vv.containerRelativeRect
|
||||
|
||||
var mode = VirtualViewMode.Hidden
|
||||
var thresholdRect = emptyRect
|
||||
when {
|
||||
rect.isEmpty -> {}
|
||||
rectsOverlap(rect, visibleRect) -> {
|
||||
mode = VirtualViewMode.Visible
|
||||
thresholdRect = visibleRect
|
||||
vv.onModeChange(VirtualViewMode.Visible, visibleRect)
|
||||
}
|
||||
rectsOverlap(rect, prerenderRect) -> {
|
||||
mode = VirtualViewMode.Prerender
|
||||
thresholdRect = prerenderRect
|
||||
vv.onModeChange(VirtualViewMode.Prerender, prerenderRect)
|
||||
}
|
||||
else -> {
|
||||
vv.onModeChange(VirtualViewMode.Hidden, emptyRect)
|
||||
}
|
||||
else -> {}
|
||||
}
|
||||
|
||||
debugLog(
|
||||
"updateModes",
|
||||
{ "virtualView=${vv.virtualViewID} mode=$mode rect=$rect thresholdRect=$thresholdRect" })
|
||||
vv.onModeChange(mode, thresholdRect)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+23
-36
@@ -34,7 +34,6 @@ public class ReactVirtualViewExperimental(context: Context) :
|
||||
override val containerRelativeRect: Rect = Rect()
|
||||
private var offsetX: Int = 0
|
||||
private var offsetY: Int = 0
|
||||
private var hadLayout: Boolean = false
|
||||
|
||||
internal val nativeId: String?
|
||||
get() = getTag(R.id.view_tag_native_id) as? String
|
||||
@@ -46,20 +45,14 @@ public class ReactVirtualViewExperimental(context: Context) :
|
||||
|
||||
@VisibleForTesting
|
||||
internal fun doAttachedToWindow() {
|
||||
scrollView = getScrollView()
|
||||
// onAttachedToWindow is usually called before layout but there are cases where it's called
|
||||
// after. If called after, we need to report the updated layout to the VirtualViewContainer
|
||||
if (hadLayout) {
|
||||
updateParentOffset()
|
||||
reportChangeToContainer()
|
||||
}
|
||||
// Assuming that layout has been called before this
|
||||
scrollView = getScrollView()?.also { scrollView?.virtualViewContainerState?.add(this) }
|
||||
}
|
||||
|
||||
/** From [View#onLayout] */
|
||||
// This is when the view itself has layout changes
|
||||
override fun onLayout(changed: Boolean, left: Int, top: Int, right: Int, bottom: Int) {
|
||||
super.onLayout(changed, left, top, right, bottom)
|
||||
hadLayout = true
|
||||
if (changed) {
|
||||
containerRelativeRect.set(
|
||||
left + offsetX,
|
||||
@@ -67,7 +60,7 @@ public class ReactVirtualViewExperimental(context: Context) :
|
||||
right + offsetX,
|
||||
bottom + offsetY,
|
||||
)
|
||||
reportChangeToContainer()
|
||||
updateContainer()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -84,8 +77,24 @@ public class ReactVirtualViewExperimental(context: Context) :
|
||||
oldBottom: Int
|
||||
) {
|
||||
if (oldLeft != left || oldTop != top) {
|
||||
updateParentOffset()
|
||||
reportChangeToContainer()
|
||||
val virtualViewScrollView = scrollView ?: return
|
||||
offsetX = 0
|
||||
offsetY = 0
|
||||
var parent: ViewParent? = parent
|
||||
while (parent != null && parent != virtualViewScrollView) {
|
||||
if (parent is View) {
|
||||
offsetX += parent.left
|
||||
offsetY += parent.top
|
||||
}
|
||||
parent = parent.parent
|
||||
}
|
||||
containerRelativeRect.set(
|
||||
left + offsetX,
|
||||
top + offsetY,
|
||||
right + offsetX,
|
||||
bottom + offsetY,
|
||||
)
|
||||
updateContainer()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -100,8 +109,6 @@ public class ReactVirtualViewExperimental(context: Context) :
|
||||
scrollView = null
|
||||
mode = null
|
||||
modeChangeEmitter = null
|
||||
hadLayout = false
|
||||
containerRelativeRect.setEmpty()
|
||||
}
|
||||
|
||||
override val virtualViewID: String
|
||||
@@ -149,28 +156,8 @@ public class ReactVirtualViewExperimental(context: Context) :
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateParentOffset() {
|
||||
val virtualViewScrollView = scrollView ?: return
|
||||
offsetX = 0
|
||||
offsetY = 0
|
||||
var parent: ViewParent? = parent
|
||||
while (parent != null && parent != virtualViewScrollView) {
|
||||
if (parent is View) {
|
||||
offsetX += parent.left
|
||||
offsetY += parent.top
|
||||
}
|
||||
parent = parent.parent
|
||||
}
|
||||
containerRelativeRect.set(
|
||||
left + offsetX,
|
||||
top + offsetY,
|
||||
right + offsetX,
|
||||
bottom + offsetY,
|
||||
)
|
||||
}
|
||||
|
||||
private fun reportChangeToContainer() {
|
||||
scrollView?.virtualViewContainerState?.onChange(this)
|
||||
private fun updateContainer() {
|
||||
scrollView?.virtualViewContainerState?.update(this)
|
||||
}
|
||||
|
||||
private fun getScrollView(): VirtualViewContainer? = traverseParentStack(true)
|
||||
|
||||
+1
-71
@@ -4,7 +4,7 @@
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @generated SignedSource<<f310a5dc27fd655eab4445cb25d4c85c>>
|
||||
* @generated SignedSource<<116217d3620e8ba52a6e0427a0d46fde>>
|
||||
*/
|
||||
|
||||
/**
|
||||
@@ -171,12 +171,6 @@ class ReactNativeFeatureFlagsJavaProvider
|
||||
return method(javaProvider_);
|
||||
}
|
||||
|
||||
bool enableImmediateUpdateModeForContentOffsetChanges() override {
|
||||
static const auto method =
|
||||
getReactNativeFeatureFlagsProviderJavaClass()->getMethod<jboolean()>("enableImmediateUpdateModeForContentOffsetChanges");
|
||||
return method(javaProvider_);
|
||||
}
|
||||
|
||||
bool enableInteropViewManagerClassLookUpOptimizationIOS() override {
|
||||
static const auto method =
|
||||
getReactNativeFeatureFlagsProviderJavaClass()->getMethod<jboolean()>("enableInteropViewManagerClassLookUpOptimizationIOS");
|
||||
@@ -315,24 +309,12 @@ class ReactNativeFeatureFlagsJavaProvider
|
||||
return method(javaProvider_);
|
||||
}
|
||||
|
||||
bool preventShadowTreeCommitExhaustionWithLocking() override {
|
||||
static const auto method =
|
||||
getReactNativeFeatureFlagsProviderJavaClass()->getMethod<jboolean()>("preventShadowTreeCommitExhaustionWithLocking");
|
||||
return method(javaProvider_);
|
||||
}
|
||||
|
||||
bool releaseImageDataWhenConsumed() override {
|
||||
static const auto method =
|
||||
getReactNativeFeatureFlagsProviderJavaClass()->getMethod<jboolean()>("releaseImageDataWhenConsumed");
|
||||
return method(javaProvider_);
|
||||
}
|
||||
|
||||
bool skipActivityIdentityAssertionOnHostPause() override {
|
||||
static const auto method =
|
||||
getReactNativeFeatureFlagsProviderJavaClass()->getMethod<jboolean()>("skipActivityIdentityAssertionOnHostPause");
|
||||
return method(javaProvider_);
|
||||
}
|
||||
|
||||
bool traceTurboModulePromiseRejectionsOnAndroid() override {
|
||||
static const auto method =
|
||||
getReactNativeFeatureFlagsProviderJavaClass()->getMethod<jboolean()>("traceTurboModulePromiseRejectionsOnAndroid");
|
||||
@@ -357,18 +339,6 @@ class ReactNativeFeatureFlagsJavaProvider
|
||||
return method(javaProvider_);
|
||||
}
|
||||
|
||||
bool useNativeEqualsInNativeReadableArrayAndroid() override {
|
||||
static const auto method =
|
||||
getReactNativeFeatureFlagsProviderJavaClass()->getMethod<jboolean()>("useNativeEqualsInNativeReadableArrayAndroid");
|
||||
return method(javaProvider_);
|
||||
}
|
||||
|
||||
bool useNativeTransformHelperAndroid() override {
|
||||
static const auto method =
|
||||
getReactNativeFeatureFlagsProviderJavaClass()->getMethod<jboolean()>("useNativeTransformHelperAndroid");
|
||||
return method(javaProvider_);
|
||||
}
|
||||
|
||||
bool useNativeViewConfigsInBridgelessMode() override {
|
||||
static const auto method =
|
||||
getReactNativeFeatureFlagsProviderJavaClass()->getMethod<jboolean()>("useNativeViewConfigsInBridgelessMode");
|
||||
@@ -525,11 +495,6 @@ bool JReactNativeFeatureFlagsCxxInterop::enableIOSViewClipToPaddingBox(
|
||||
return ReactNativeFeatureFlags::enableIOSViewClipToPaddingBox();
|
||||
}
|
||||
|
||||
bool JReactNativeFeatureFlagsCxxInterop::enableImmediateUpdateModeForContentOffsetChanges(
|
||||
facebook::jni::alias_ref<JReactNativeFeatureFlagsCxxInterop> /*unused*/) {
|
||||
return ReactNativeFeatureFlags::enableImmediateUpdateModeForContentOffsetChanges();
|
||||
}
|
||||
|
||||
bool JReactNativeFeatureFlagsCxxInterop::enableInteropViewManagerClassLookUpOptimizationIOS(
|
||||
facebook::jni::alias_ref<JReactNativeFeatureFlagsCxxInterop> /*unused*/) {
|
||||
return ReactNativeFeatureFlags::enableInteropViewManagerClassLookUpOptimizationIOS();
|
||||
@@ -645,21 +610,11 @@ double JReactNativeFeatureFlagsCxxInterop::preparedTextCacheSize(
|
||||
return ReactNativeFeatureFlags::preparedTextCacheSize();
|
||||
}
|
||||
|
||||
bool JReactNativeFeatureFlagsCxxInterop::preventShadowTreeCommitExhaustionWithLocking(
|
||||
facebook::jni::alias_ref<JReactNativeFeatureFlagsCxxInterop> /*unused*/) {
|
||||
return ReactNativeFeatureFlags::preventShadowTreeCommitExhaustionWithLocking();
|
||||
}
|
||||
|
||||
bool JReactNativeFeatureFlagsCxxInterop::releaseImageDataWhenConsumed(
|
||||
facebook::jni::alias_ref<JReactNativeFeatureFlagsCxxInterop> /*unused*/) {
|
||||
return ReactNativeFeatureFlags::releaseImageDataWhenConsumed();
|
||||
}
|
||||
|
||||
bool JReactNativeFeatureFlagsCxxInterop::skipActivityIdentityAssertionOnHostPause(
|
||||
facebook::jni::alias_ref<JReactNativeFeatureFlagsCxxInterop> /*unused*/) {
|
||||
return ReactNativeFeatureFlags::skipActivityIdentityAssertionOnHostPause();
|
||||
}
|
||||
|
||||
bool JReactNativeFeatureFlagsCxxInterop::traceTurboModulePromiseRejectionsOnAndroid(
|
||||
facebook::jni::alias_ref<JReactNativeFeatureFlagsCxxInterop> /*unused*/) {
|
||||
return ReactNativeFeatureFlags::traceTurboModulePromiseRejectionsOnAndroid();
|
||||
@@ -680,16 +635,6 @@ bool JReactNativeFeatureFlagsCxxInterop::useFabricInterop(
|
||||
return ReactNativeFeatureFlags::useFabricInterop();
|
||||
}
|
||||
|
||||
bool JReactNativeFeatureFlagsCxxInterop::useNativeEqualsInNativeReadableArrayAndroid(
|
||||
facebook::jni::alias_ref<JReactNativeFeatureFlagsCxxInterop> /*unused*/) {
|
||||
return ReactNativeFeatureFlags::useNativeEqualsInNativeReadableArrayAndroid();
|
||||
}
|
||||
|
||||
bool JReactNativeFeatureFlagsCxxInterop::useNativeTransformHelperAndroid(
|
||||
facebook::jni::alias_ref<JReactNativeFeatureFlagsCxxInterop> /*unused*/) {
|
||||
return ReactNativeFeatureFlags::useNativeTransformHelperAndroid();
|
||||
}
|
||||
|
||||
bool JReactNativeFeatureFlagsCxxInterop::useNativeViewConfigsInBridgelessMode(
|
||||
facebook::jni::alias_ref<JReactNativeFeatureFlagsCxxInterop> /*unused*/) {
|
||||
return ReactNativeFeatureFlags::useNativeViewConfigsInBridgelessMode();
|
||||
@@ -822,9 +767,6 @@ void JReactNativeFeatureFlagsCxxInterop::registerNatives() {
|
||||
makeNativeMethod(
|
||||
"enableIOSViewClipToPaddingBox",
|
||||
JReactNativeFeatureFlagsCxxInterop::enableIOSViewClipToPaddingBox),
|
||||
makeNativeMethod(
|
||||
"enableImmediateUpdateModeForContentOffsetChanges",
|
||||
JReactNativeFeatureFlagsCxxInterop::enableImmediateUpdateModeForContentOffsetChanges),
|
||||
makeNativeMethod(
|
||||
"enableInteropViewManagerClassLookUpOptimizationIOS",
|
||||
JReactNativeFeatureFlagsCxxInterop::enableInteropViewManagerClassLookUpOptimizationIOS),
|
||||
@@ -894,15 +836,9 @@ void JReactNativeFeatureFlagsCxxInterop::registerNatives() {
|
||||
makeNativeMethod(
|
||||
"preparedTextCacheSize",
|
||||
JReactNativeFeatureFlagsCxxInterop::preparedTextCacheSize),
|
||||
makeNativeMethod(
|
||||
"preventShadowTreeCommitExhaustionWithLocking",
|
||||
JReactNativeFeatureFlagsCxxInterop::preventShadowTreeCommitExhaustionWithLocking),
|
||||
makeNativeMethod(
|
||||
"releaseImageDataWhenConsumed",
|
||||
JReactNativeFeatureFlagsCxxInterop::releaseImageDataWhenConsumed),
|
||||
makeNativeMethod(
|
||||
"skipActivityIdentityAssertionOnHostPause",
|
||||
JReactNativeFeatureFlagsCxxInterop::skipActivityIdentityAssertionOnHostPause),
|
||||
makeNativeMethod(
|
||||
"traceTurboModulePromiseRejectionsOnAndroid",
|
||||
JReactNativeFeatureFlagsCxxInterop::traceTurboModulePromiseRejectionsOnAndroid),
|
||||
@@ -915,12 +851,6 @@ void JReactNativeFeatureFlagsCxxInterop::registerNatives() {
|
||||
makeNativeMethod(
|
||||
"useFabricInterop",
|
||||
JReactNativeFeatureFlagsCxxInterop::useFabricInterop),
|
||||
makeNativeMethod(
|
||||
"useNativeEqualsInNativeReadableArrayAndroid",
|
||||
JReactNativeFeatureFlagsCxxInterop::useNativeEqualsInNativeReadableArrayAndroid),
|
||||
makeNativeMethod(
|
||||
"useNativeTransformHelperAndroid",
|
||||
JReactNativeFeatureFlagsCxxInterop::useNativeTransformHelperAndroid),
|
||||
makeNativeMethod(
|
||||
"useNativeViewConfigsInBridgelessMode",
|
||||
JReactNativeFeatureFlagsCxxInterop::useNativeViewConfigsInBridgelessMode),
|
||||
|
||||
+1
-16
@@ -4,7 +4,7 @@
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @generated SignedSource<<8c1da07c0b7d2053f7fdaac4326c3ac1>>
|
||||
* @generated SignedSource<<96750d4cfdb356392256a175a3c740ef>>
|
||||
*/
|
||||
|
||||
/**
|
||||
@@ -96,9 +96,6 @@ class JReactNativeFeatureFlagsCxxInterop
|
||||
static bool enableIOSViewClipToPaddingBox(
|
||||
facebook::jni::alias_ref<JReactNativeFeatureFlagsCxxInterop>);
|
||||
|
||||
static bool enableImmediateUpdateModeForContentOffsetChanges(
|
||||
facebook::jni::alias_ref<JReactNativeFeatureFlagsCxxInterop>);
|
||||
|
||||
static bool enableInteropViewManagerClassLookUpOptimizationIOS(
|
||||
facebook::jni::alias_ref<JReactNativeFeatureFlagsCxxInterop>);
|
||||
|
||||
@@ -168,15 +165,9 @@ class JReactNativeFeatureFlagsCxxInterop
|
||||
static double preparedTextCacheSize(
|
||||
facebook::jni::alias_ref<JReactNativeFeatureFlagsCxxInterop>);
|
||||
|
||||
static bool preventShadowTreeCommitExhaustionWithLocking(
|
||||
facebook::jni::alias_ref<JReactNativeFeatureFlagsCxxInterop>);
|
||||
|
||||
static bool releaseImageDataWhenConsumed(
|
||||
facebook::jni::alias_ref<JReactNativeFeatureFlagsCxxInterop>);
|
||||
|
||||
static bool skipActivityIdentityAssertionOnHostPause(
|
||||
facebook::jni::alias_ref<JReactNativeFeatureFlagsCxxInterop>);
|
||||
|
||||
static bool traceTurboModulePromiseRejectionsOnAndroid(
|
||||
facebook::jni::alias_ref<JReactNativeFeatureFlagsCxxInterop>);
|
||||
|
||||
@@ -189,12 +180,6 @@ class JReactNativeFeatureFlagsCxxInterop
|
||||
static bool useFabricInterop(
|
||||
facebook::jni::alias_ref<JReactNativeFeatureFlagsCxxInterop>);
|
||||
|
||||
static bool useNativeEqualsInNativeReadableArrayAndroid(
|
||||
facebook::jni::alias_ref<JReactNativeFeatureFlagsCxxInterop>);
|
||||
|
||||
static bool useNativeTransformHelperAndroid(
|
||||
facebook::jni::alias_ref<JReactNativeFeatureFlagsCxxInterop>);
|
||||
|
||||
static bool useNativeViewConfigsInBridgelessMode(
|
||||
facebook::jni::alias_ref<JReactNativeFeatureFlagsCxxInterop>);
|
||||
|
||||
|
||||
@@ -31,14 +31,13 @@ add_library(
|
||||
OnLoad-common.cpp
|
||||
ReadableNativeArray.cpp
|
||||
ReadableNativeMap.cpp
|
||||
TransformHelper.cpp
|
||||
WritableNativeArray.cpp
|
||||
WritableNativeMap.cpp
|
||||
)
|
||||
target_merge_so(reactnativejni_common)
|
||||
target_include_directories(reactnativejni_common PUBLIC ../../)
|
||||
|
||||
target_link_libraries(reactnativejni_common fbjni folly_runtime react_cxxreact rrc_view)
|
||||
target_link_libraries(reactnativejni_common fbjni folly_runtime react_cxxreact)
|
||||
target_compile_reactnative_options(reactnativejni_common PRIVATE)
|
||||
target_compile_options(reactnativejni_common PRIVATE -Wno-unused-lambda-capture)
|
||||
|
||||
|
||||
@@ -21,10 +21,6 @@ class NativeArray : public jni::HybridClass<NativeArray> {
|
||||
|
||||
jni::local_ref<jstring> toString();
|
||||
|
||||
const folly::dynamic& getArray() const {
|
||||
return array_;
|
||||
}
|
||||
|
||||
RN_EXPORT folly::dynamic consume();
|
||||
|
||||
// Whether this array has been added to another array or map and no longer
|
||||
|
||||
@@ -11,7 +11,6 @@
|
||||
#include "JReactMarker.h"
|
||||
#include "NativeArray.h"
|
||||
#include "NativeMap.h"
|
||||
#include "TransformHelper.h"
|
||||
#include "WritableNativeArray.h"
|
||||
#include "WritableNativeMap.h"
|
||||
|
||||
@@ -28,7 +27,6 @@ extern "C" JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved) {
|
||||
ReadableNativeMap::registerNatives();
|
||||
WritableNativeArray::registerNatives();
|
||||
WritableNativeMap::registerNatives();
|
||||
TransformHelper::registerNatives();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -40,16 +40,10 @@ local_ref<JArrayClass<jobject>> ReadableNativeArray::importTypeArray() {
|
||||
return jarray;
|
||||
}
|
||||
|
||||
bool ReadableNativeArray::equals(
|
||||
jni::alias_ref<ReadableNativeArray::javaobject> other) {
|
||||
return array_ == other->cthis()->array_;
|
||||
}
|
||||
|
||||
void ReadableNativeArray::registerNatives() {
|
||||
registerHybrid({
|
||||
makeNativeMethod("importArray", ReadableNativeArray::importArray),
|
||||
makeNativeMethod("importTypeArray", ReadableNativeArray::importTypeArray),
|
||||
makeNativeMethod("nativeEquals", ReadableNativeArray::equals),
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -35,7 +35,6 @@ class ReadableNativeArray
|
||||
static void mapException(std::exception_ptr ex);
|
||||
static void registerNatives();
|
||||
|
||||
bool equals(jni::alias_ref<ReadableNativeArray::javaobject> other);
|
||||
jni::local_ref<jni::JArrayClass<jobject>> importArray();
|
||||
jni::local_ref<jni::JArrayClass<jobject>> importTypeArray();
|
||||
};
|
||||
|
||||
@@ -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 "TransformHelper.h"
|
||||
|
||||
#include <react/renderer/components/view/BaseViewProps.h>
|
||||
#include <react/renderer/components/view/conversions.h>
|
||||
|
||||
#include "NativeArray.h"
|
||||
|
||||
using namespace facebook::jni;
|
||||
|
||||
namespace facebook::react {
|
||||
|
||||
namespace {
|
||||
void processTransform(
|
||||
jni::alias_ref<jclass> /*unused*/,
|
||||
NativeArray* jTransforms,
|
||||
jni::alias_ref<jni::JArrayDouble> jResult,
|
||||
float viewWidth,
|
||||
float viewHeight,
|
||||
NativeArray* jTransformOrigin) {
|
||||
// Assuming parsing transforms doesn't require a real PropsParserContext
|
||||
static ContextContainer contextContainer;
|
||||
static PropsParserContext context(0, contextContainer);
|
||||
|
||||
RawValue transformValue(jTransforms->getArray());
|
||||
Transform transform;
|
||||
fromRawValue(context, transformValue, transform);
|
||||
|
||||
TransformOrigin transformOrigin;
|
||||
if (jTransformOrigin != nullptr) {
|
||||
RawValue transformOriginValue(jTransformOrigin->getArray());
|
||||
fromRawValue(context, transformOriginValue, transformOrigin);
|
||||
}
|
||||
|
||||
auto result = BaseViewProps::resolveTransform(
|
||||
Size(viewWidth, viewHeight), transform, transformOrigin);
|
||||
|
||||
// Convert from matrix of floats to double matrix
|
||||
constexpr size_t MatrixSize = std::tuple_size_v<decltype(result.matrix)>;
|
||||
std::array<double, MatrixSize> doubleTransform{};
|
||||
std::copy(
|
||||
result.matrix.begin(), result.matrix.end(), doubleTransform.begin());
|
||||
jResult->setRegion(0, MatrixSize, doubleTransform.data());
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
void TransformHelper::registerNatives() {
|
||||
javaClassLocal()->registerNatives({
|
||||
makeNativeMethod("nativeProcessTransform", processTransform),
|
||||
});
|
||||
}
|
||||
|
||||
} // namespace facebook::react
|
||||
@@ -1,22 +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>
|
||||
|
||||
namespace facebook::react {
|
||||
|
||||
class TransformHelper : public jni::JavaClass<TransformHelper> {
|
||||
public:
|
||||
static auto constexpr* kJavaDescriptor =
|
||||
"Lcom/facebook/react/uimanager/TransformHelper;";
|
||||
|
||||
static void registerNatives();
|
||||
};
|
||||
|
||||
} // namespace facebook::react
|
||||
@@ -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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace facebook::react::jsinspector_modern {
|
||||
|
||||
/**
|
||||
* https://developer.chrome.com/docs/devtools/performance/extension?utm_source=devtools#devtools_object
|
||||
*/
|
||||
struct DevToolsTrackEntryPayload {
|
||||
std::string track;
|
||||
};
|
||||
|
||||
} // namespace facebook::react::jsinspector_modern
|
||||
@@ -113,8 +113,7 @@ void PerformanceTracer::collectEvents(
|
||||
|
||||
void PerformanceTracer::reportMark(
|
||||
const std::string_view& name,
|
||||
HighResTimeStamp start,
|
||||
folly::dynamic&& detail) {
|
||||
HighResTimeStamp start) {
|
||||
if (!tracingAtomic_) {
|
||||
return;
|
||||
}
|
||||
@@ -124,13 +123,6 @@ void PerformanceTracer::reportMark(
|
||||
return;
|
||||
}
|
||||
|
||||
folly::dynamic eventArgs = folly::dynamic::object();
|
||||
if (detail != nullptr) {
|
||||
eventArgs = folly::dynamic::object(
|
||||
"data",
|
||||
folly::dynamic::object("detail", folly::toJson(std::move(detail))));
|
||||
}
|
||||
|
||||
buffer_.emplace_back(TraceEvent{
|
||||
.name = std::string(name),
|
||||
.cat = "blink.user_timing",
|
||||
@@ -138,7 +130,6 @@ void PerformanceTracer::reportMark(
|
||||
.ts = start,
|
||||
.pid = processId_,
|
||||
.tid = oscompat::getCurrentThreadId(),
|
||||
.args = eventArgs,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -146,15 +137,18 @@ void PerformanceTracer::reportMeasure(
|
||||
const std::string_view& name,
|
||||
HighResTimeStamp start,
|
||||
HighResDuration duration,
|
||||
folly::dynamic&& detail) {
|
||||
const std::optional<DevToolsTrackEntryPayload>& trackMetadata) {
|
||||
if (!tracingAtomic_) {
|
||||
return;
|
||||
}
|
||||
|
||||
folly::dynamic beginEventArgs = folly::dynamic::object();
|
||||
if (detail != nullptr) {
|
||||
if (trackMetadata.has_value()) {
|
||||
folly::dynamic devtoolsObject = folly::dynamic::object(
|
||||
"devtools",
|
||||
folly::dynamic::object("track", trackMetadata.value().track));
|
||||
beginEventArgs =
|
||||
folly::dynamic::object("detail", folly::toJson(std::move(detail)));
|
||||
folly::dynamic::object("detail", folly::toJson(devtoolsObject));
|
||||
}
|
||||
|
||||
auto currentThreadId = oscompat::getCurrentThreadId();
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CdpTracing.h"
|
||||
#include "ConsoleTimeStamp.h"
|
||||
#include "TraceEvent.h"
|
||||
#include "TraceEventProfile.h"
|
||||
@@ -59,17 +60,13 @@ class PerformanceTracer {
|
||||
const std::function<void(const folly::dynamic& eventsChunk)>&
|
||||
resultCallback,
|
||||
uint16_t chunkSize);
|
||||
|
||||
/**
|
||||
* Record a `Performance.mark()` event - a labelled timestamp. If not
|
||||
* currently tracing, this is a no-op.
|
||||
*
|
||||
* See https://w3c.github.io/user-timing/#mark-method.
|
||||
*/
|
||||
void reportMark(
|
||||
const std::string_view& name,
|
||||
HighResTimeStamp start,
|
||||
folly::dynamic&& detail = nullptr);
|
||||
void reportMark(const std::string_view& name, HighResTimeStamp start);
|
||||
|
||||
/**
|
||||
* Record a `Performance.measure()` event - a labelled duration. If not
|
||||
@@ -81,7 +78,7 @@ class PerformanceTracer {
|
||||
const std::string_view& name,
|
||||
HighResTimeStamp start,
|
||||
HighResDuration duration,
|
||||
folly::dynamic&& detail = nullptr);
|
||||
const std::optional<DevToolsTrackEntryPayload>& trackMetadata);
|
||||
|
||||
/**
|
||||
* Record a "TimeStamp" Trace Event - a labelled entry on Performance
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @generated SignedSource<<355265aa8f13e3f307d6e30db6b80d41>>
|
||||
* @generated SignedSource<<8e952ab168159599f6c97fbc68dd57bb>>
|
||||
*/
|
||||
|
||||
/**
|
||||
@@ -114,10 +114,6 @@ bool ReactNativeFeatureFlags::enableIOSViewClipToPaddingBox() {
|
||||
return getAccessor().enableIOSViewClipToPaddingBox();
|
||||
}
|
||||
|
||||
bool ReactNativeFeatureFlags::enableImmediateUpdateModeForContentOffsetChanges() {
|
||||
return getAccessor().enableImmediateUpdateModeForContentOffsetChanges();
|
||||
}
|
||||
|
||||
bool ReactNativeFeatureFlags::enableInteropViewManagerClassLookUpOptimizationIOS() {
|
||||
return getAccessor().enableInteropViewManagerClassLookUpOptimizationIOS();
|
||||
}
|
||||
@@ -210,18 +206,10 @@ double ReactNativeFeatureFlags::preparedTextCacheSize() {
|
||||
return getAccessor().preparedTextCacheSize();
|
||||
}
|
||||
|
||||
bool ReactNativeFeatureFlags::preventShadowTreeCommitExhaustionWithLocking() {
|
||||
return getAccessor().preventShadowTreeCommitExhaustionWithLocking();
|
||||
}
|
||||
|
||||
bool ReactNativeFeatureFlags::releaseImageDataWhenConsumed() {
|
||||
return getAccessor().releaseImageDataWhenConsumed();
|
||||
}
|
||||
|
||||
bool ReactNativeFeatureFlags::skipActivityIdentityAssertionOnHostPause() {
|
||||
return getAccessor().skipActivityIdentityAssertionOnHostPause();
|
||||
}
|
||||
|
||||
bool ReactNativeFeatureFlags::traceTurboModulePromiseRejectionsOnAndroid() {
|
||||
return getAccessor().traceTurboModulePromiseRejectionsOnAndroid();
|
||||
}
|
||||
@@ -238,14 +226,6 @@ bool ReactNativeFeatureFlags::useFabricInterop() {
|
||||
return getAccessor().useFabricInterop();
|
||||
}
|
||||
|
||||
bool ReactNativeFeatureFlags::useNativeEqualsInNativeReadableArrayAndroid() {
|
||||
return getAccessor().useNativeEqualsInNativeReadableArrayAndroid();
|
||||
}
|
||||
|
||||
bool ReactNativeFeatureFlags::useNativeTransformHelperAndroid() {
|
||||
return getAccessor().useNativeTransformHelperAndroid();
|
||||
}
|
||||
|
||||
bool ReactNativeFeatureFlags::useNativeViewConfigsInBridgelessMode() {
|
||||
return getAccessor().useNativeViewConfigsInBridgelessMode();
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @generated SignedSource<<c584290ce61ee78bdf843c19dd40c40d>>
|
||||
* @generated SignedSource<<b6df25d8c333bf7656ade934b404020d>>
|
||||
*/
|
||||
|
||||
/**
|
||||
@@ -149,11 +149,6 @@ class ReactNativeFeatureFlags {
|
||||
*/
|
||||
RN_EXPORT static bool enableIOSViewClipToPaddingBox();
|
||||
|
||||
/**
|
||||
* Dispatches state updates for content offset changes synchronously on the main thread.
|
||||
*/
|
||||
RN_EXPORT static bool enableImmediateUpdateModeForContentOffsetChanges();
|
||||
|
||||
/**
|
||||
* This is to fix the issue with interop view manager where component descriptor lookup is causing ViewManager to preload.
|
||||
*/
|
||||
@@ -269,21 +264,11 @@ class ReactNativeFeatureFlags {
|
||||
*/
|
||||
RN_EXPORT static double preparedTextCacheSize();
|
||||
|
||||
/**
|
||||
* Enables a new mechanism in ShadowTree to prevent problems caused by multiple threads trying to commit concurrently. If a thread tries to commit a few times unsuccessfully, it will acquire a lock and try again.
|
||||
*/
|
||||
RN_EXPORT static bool preventShadowTreeCommitExhaustionWithLocking();
|
||||
|
||||
/**
|
||||
* Releases the cached image data when it is consumed by the observers.
|
||||
*/
|
||||
RN_EXPORT static bool releaseImageDataWhenConsumed();
|
||||
|
||||
/**
|
||||
* Skip activity identity assertion in ReactHostImpl::onHostPause()
|
||||
*/
|
||||
RN_EXPORT static bool skipActivityIdentityAssertionOnHostPause();
|
||||
|
||||
/**
|
||||
* Enables storing js caller stack when creating promise in native module. This is useful in case of Promise rejection and tracing the cause.
|
||||
*/
|
||||
@@ -304,16 +289,6 @@ class ReactNativeFeatureFlags {
|
||||
*/
|
||||
RN_EXPORT static bool useFabricInterop();
|
||||
|
||||
/**
|
||||
* Use a native implementation of equals in NativeReadableArray.
|
||||
*/
|
||||
RN_EXPORT static bool useNativeEqualsInNativeReadableArrayAndroid();
|
||||
|
||||
/**
|
||||
* Use a native implementation of TransformHelper
|
||||
*/
|
||||
RN_EXPORT static bool useNativeTransformHelperAndroid();
|
||||
|
||||
/**
|
||||
* When enabled, the native view configs are used in bridgeless mode.
|
||||
*/
|
||||
|
||||
+36
-126
@@ -4,7 +4,7 @@
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @generated SignedSource<<dc5c6b3273ef312426c4ac366cc13772>>
|
||||
* @generated SignedSource<<074c50ff00ac8dcc6ff0d766ce44bd53>>
|
||||
*/
|
||||
|
||||
/**
|
||||
@@ -425,24 +425,6 @@ bool ReactNativeFeatureFlagsAccessor::enableIOSViewClipToPaddingBox() {
|
||||
return flagValue.value();
|
||||
}
|
||||
|
||||
bool ReactNativeFeatureFlagsAccessor::enableImmediateUpdateModeForContentOffsetChanges() {
|
||||
auto flagValue = enableImmediateUpdateModeForContentOffsetChanges_.load();
|
||||
|
||||
if (!flagValue.has_value()) {
|
||||
// This block is not exclusive but it is not necessary.
|
||||
// If multiple threads try to initialize the feature flag, we would only
|
||||
// be accessing the provider multiple times but the end state of this
|
||||
// instance and the returned flag value would be the same.
|
||||
|
||||
markFlagAsAccessed(22, "enableImmediateUpdateModeForContentOffsetChanges");
|
||||
|
||||
flagValue = currentProvider_->enableImmediateUpdateModeForContentOffsetChanges();
|
||||
enableImmediateUpdateModeForContentOffsetChanges_ = flagValue;
|
||||
}
|
||||
|
||||
return flagValue.value();
|
||||
}
|
||||
|
||||
bool ReactNativeFeatureFlagsAccessor::enableInteropViewManagerClassLookUpOptimizationIOS() {
|
||||
auto flagValue = enableInteropViewManagerClassLookUpOptimizationIOS_.load();
|
||||
|
||||
@@ -452,7 +434,7 @@ bool ReactNativeFeatureFlagsAccessor::enableInteropViewManagerClassLookUpOptimiz
|
||||
// be accessing the provider multiple times but the end state of this
|
||||
// instance and the returned flag value would be the same.
|
||||
|
||||
markFlagAsAccessed(23, "enableInteropViewManagerClassLookUpOptimizationIOS");
|
||||
markFlagAsAccessed(22, "enableInteropViewManagerClassLookUpOptimizationIOS");
|
||||
|
||||
flagValue = currentProvider_->enableInteropViewManagerClassLookUpOptimizationIOS();
|
||||
enableInteropViewManagerClassLookUpOptimizationIOS_ = flagValue;
|
||||
@@ -470,7 +452,7 @@ bool ReactNativeFeatureFlagsAccessor::enableLayoutAnimationsOnAndroid() {
|
||||
// be accessing the provider multiple times but the end state of this
|
||||
// instance and the returned flag value would be the same.
|
||||
|
||||
markFlagAsAccessed(24, "enableLayoutAnimationsOnAndroid");
|
||||
markFlagAsAccessed(23, "enableLayoutAnimationsOnAndroid");
|
||||
|
||||
flagValue = currentProvider_->enableLayoutAnimationsOnAndroid();
|
||||
enableLayoutAnimationsOnAndroid_ = flagValue;
|
||||
@@ -488,7 +470,7 @@ bool ReactNativeFeatureFlagsAccessor::enableLayoutAnimationsOnIOS() {
|
||||
// be accessing the provider multiple times but the end state of this
|
||||
// instance and the returned flag value would be the same.
|
||||
|
||||
markFlagAsAccessed(25, "enableLayoutAnimationsOnIOS");
|
||||
markFlagAsAccessed(24, "enableLayoutAnimationsOnIOS");
|
||||
|
||||
flagValue = currentProvider_->enableLayoutAnimationsOnIOS();
|
||||
enableLayoutAnimationsOnIOS_ = flagValue;
|
||||
@@ -506,7 +488,7 @@ bool ReactNativeFeatureFlagsAccessor::enableMainQueueCoordinatorOnIOS() {
|
||||
// be accessing the provider multiple times but the end state of this
|
||||
// instance and the returned flag value would be the same.
|
||||
|
||||
markFlagAsAccessed(26, "enableMainQueueCoordinatorOnIOS");
|
||||
markFlagAsAccessed(25, "enableMainQueueCoordinatorOnIOS");
|
||||
|
||||
flagValue = currentProvider_->enableMainQueueCoordinatorOnIOS();
|
||||
enableMainQueueCoordinatorOnIOS_ = flagValue;
|
||||
@@ -524,7 +506,7 @@ bool ReactNativeFeatureFlagsAccessor::enableModuleArgumentNSNullConversionIOS()
|
||||
// be accessing the provider multiple times but the end state of this
|
||||
// instance and the returned flag value would be the same.
|
||||
|
||||
markFlagAsAccessed(27, "enableModuleArgumentNSNullConversionIOS");
|
||||
markFlagAsAccessed(26, "enableModuleArgumentNSNullConversionIOS");
|
||||
|
||||
flagValue = currentProvider_->enableModuleArgumentNSNullConversionIOS();
|
||||
enableModuleArgumentNSNullConversionIOS_ = flagValue;
|
||||
@@ -542,7 +524,7 @@ bool ReactNativeFeatureFlagsAccessor::enableNativeCSSParsing() {
|
||||
// be accessing the provider multiple times but the end state of this
|
||||
// instance and the returned flag value would be the same.
|
||||
|
||||
markFlagAsAccessed(28, "enableNativeCSSParsing");
|
||||
markFlagAsAccessed(27, "enableNativeCSSParsing");
|
||||
|
||||
flagValue = currentProvider_->enableNativeCSSParsing();
|
||||
enableNativeCSSParsing_ = flagValue;
|
||||
@@ -560,7 +542,7 @@ bool ReactNativeFeatureFlagsAccessor::enableNetworkEventReporting() {
|
||||
// be accessing the provider multiple times but the end state of this
|
||||
// instance and the returned flag value would be the same.
|
||||
|
||||
markFlagAsAccessed(29, "enableNetworkEventReporting");
|
||||
markFlagAsAccessed(28, "enableNetworkEventReporting");
|
||||
|
||||
flagValue = currentProvider_->enableNetworkEventReporting();
|
||||
enableNetworkEventReporting_ = flagValue;
|
||||
@@ -578,7 +560,7 @@ bool ReactNativeFeatureFlagsAccessor::enableNewBackgroundAndBorderDrawables() {
|
||||
// be accessing the provider multiple times but the end state of this
|
||||
// instance and the returned flag value would be the same.
|
||||
|
||||
markFlagAsAccessed(30, "enableNewBackgroundAndBorderDrawables");
|
||||
markFlagAsAccessed(29, "enableNewBackgroundAndBorderDrawables");
|
||||
|
||||
flagValue = currentProvider_->enableNewBackgroundAndBorderDrawables();
|
||||
enableNewBackgroundAndBorderDrawables_ = flagValue;
|
||||
@@ -596,7 +578,7 @@ bool ReactNativeFeatureFlagsAccessor::enablePreparedTextLayout() {
|
||||
// be accessing the provider multiple times but the end state of this
|
||||
// instance and the returned flag value would be the same.
|
||||
|
||||
markFlagAsAccessed(31, "enablePreparedTextLayout");
|
||||
markFlagAsAccessed(30, "enablePreparedTextLayout");
|
||||
|
||||
flagValue = currentProvider_->enablePreparedTextLayout();
|
||||
enablePreparedTextLayout_ = flagValue;
|
||||
@@ -614,7 +596,7 @@ bool ReactNativeFeatureFlagsAccessor::enablePropsUpdateReconciliationAndroid() {
|
||||
// be accessing the provider multiple times but the end state of this
|
||||
// instance and the returned flag value would be the same.
|
||||
|
||||
markFlagAsAccessed(32, "enablePropsUpdateReconciliationAndroid");
|
||||
markFlagAsAccessed(31, "enablePropsUpdateReconciliationAndroid");
|
||||
|
||||
flagValue = currentProvider_->enablePropsUpdateReconciliationAndroid();
|
||||
enablePropsUpdateReconciliationAndroid_ = flagValue;
|
||||
@@ -632,7 +614,7 @@ bool ReactNativeFeatureFlagsAccessor::enableResourceTimingAPI() {
|
||||
// be accessing the provider multiple times but the end state of this
|
||||
// instance and the returned flag value would be the same.
|
||||
|
||||
markFlagAsAccessed(33, "enableResourceTimingAPI");
|
||||
markFlagAsAccessed(32, "enableResourceTimingAPI");
|
||||
|
||||
flagValue = currentProvider_->enableResourceTimingAPI();
|
||||
enableResourceTimingAPI_ = flagValue;
|
||||
@@ -650,7 +632,7 @@ bool ReactNativeFeatureFlagsAccessor::enableViewCulling() {
|
||||
// be accessing the provider multiple times but the end state of this
|
||||
// instance and the returned flag value would be the same.
|
||||
|
||||
markFlagAsAccessed(34, "enableViewCulling");
|
||||
markFlagAsAccessed(33, "enableViewCulling");
|
||||
|
||||
flagValue = currentProvider_->enableViewCulling();
|
||||
enableViewCulling_ = flagValue;
|
||||
@@ -668,7 +650,7 @@ bool ReactNativeFeatureFlagsAccessor::enableViewRecycling() {
|
||||
// be accessing the provider multiple times but the end state of this
|
||||
// instance and the returned flag value would be the same.
|
||||
|
||||
markFlagAsAccessed(35, "enableViewRecycling");
|
||||
markFlagAsAccessed(34, "enableViewRecycling");
|
||||
|
||||
flagValue = currentProvider_->enableViewRecycling();
|
||||
enableViewRecycling_ = flagValue;
|
||||
@@ -686,7 +668,7 @@ bool ReactNativeFeatureFlagsAccessor::enableViewRecyclingForText() {
|
||||
// be accessing the provider multiple times but the end state of this
|
||||
// instance and the returned flag value would be the same.
|
||||
|
||||
markFlagAsAccessed(36, "enableViewRecyclingForText");
|
||||
markFlagAsAccessed(35, "enableViewRecyclingForText");
|
||||
|
||||
flagValue = currentProvider_->enableViewRecyclingForText();
|
||||
enableViewRecyclingForText_ = flagValue;
|
||||
@@ -704,7 +686,7 @@ bool ReactNativeFeatureFlagsAccessor::enableViewRecyclingForView() {
|
||||
// be accessing the provider multiple times but the end state of this
|
||||
// instance and the returned flag value would be the same.
|
||||
|
||||
markFlagAsAccessed(37, "enableViewRecyclingForView");
|
||||
markFlagAsAccessed(36, "enableViewRecyclingForView");
|
||||
|
||||
flagValue = currentProvider_->enableViewRecyclingForView();
|
||||
enableViewRecyclingForView_ = flagValue;
|
||||
@@ -722,7 +704,7 @@ bool ReactNativeFeatureFlagsAccessor::enableVirtualViewDebugFeatures() {
|
||||
// be accessing the provider multiple times but the end state of this
|
||||
// instance and the returned flag value would be the same.
|
||||
|
||||
markFlagAsAccessed(38, "enableVirtualViewDebugFeatures");
|
||||
markFlagAsAccessed(37, "enableVirtualViewDebugFeatures");
|
||||
|
||||
flagValue = currentProvider_->enableVirtualViewDebugFeatures();
|
||||
enableVirtualViewDebugFeatures_ = flagValue;
|
||||
@@ -740,7 +722,7 @@ bool ReactNativeFeatureFlagsAccessor::enableVirtualViewRenderState() {
|
||||
// be accessing the provider multiple times but the end state of this
|
||||
// instance and the returned flag value would be the same.
|
||||
|
||||
markFlagAsAccessed(39, "enableVirtualViewRenderState");
|
||||
markFlagAsAccessed(38, "enableVirtualViewRenderState");
|
||||
|
||||
flagValue = currentProvider_->enableVirtualViewRenderState();
|
||||
enableVirtualViewRenderState_ = flagValue;
|
||||
@@ -758,7 +740,7 @@ bool ReactNativeFeatureFlagsAccessor::enableVirtualViewWindowFocusDetection() {
|
||||
// be accessing the provider multiple times but the end state of this
|
||||
// instance and the returned flag value would be the same.
|
||||
|
||||
markFlagAsAccessed(40, "enableVirtualViewWindowFocusDetection");
|
||||
markFlagAsAccessed(39, "enableVirtualViewWindowFocusDetection");
|
||||
|
||||
flagValue = currentProvider_->enableVirtualViewWindowFocusDetection();
|
||||
enableVirtualViewWindowFocusDetection_ = flagValue;
|
||||
@@ -776,7 +758,7 @@ bool ReactNativeFeatureFlagsAccessor::fixMappingOfEventPrioritiesBetweenFabricAn
|
||||
// be accessing the provider multiple times but the end state of this
|
||||
// instance and the returned flag value would be the same.
|
||||
|
||||
markFlagAsAccessed(41, "fixMappingOfEventPrioritiesBetweenFabricAndReact");
|
||||
markFlagAsAccessed(40, "fixMappingOfEventPrioritiesBetweenFabricAndReact");
|
||||
|
||||
flagValue = currentProvider_->fixMappingOfEventPrioritiesBetweenFabricAndReact();
|
||||
fixMappingOfEventPrioritiesBetweenFabricAndReact_ = flagValue;
|
||||
@@ -794,7 +776,7 @@ bool ReactNativeFeatureFlagsAccessor::fuseboxEnabledRelease() {
|
||||
// be accessing the provider multiple times but the end state of this
|
||||
// instance and the returned flag value would be the same.
|
||||
|
||||
markFlagAsAccessed(42, "fuseboxEnabledRelease");
|
||||
markFlagAsAccessed(41, "fuseboxEnabledRelease");
|
||||
|
||||
flagValue = currentProvider_->fuseboxEnabledRelease();
|
||||
fuseboxEnabledRelease_ = flagValue;
|
||||
@@ -812,7 +794,7 @@ bool ReactNativeFeatureFlagsAccessor::fuseboxNetworkInspectionEnabled() {
|
||||
// be accessing the provider multiple times but the end state of this
|
||||
// instance and the returned flag value would be the same.
|
||||
|
||||
markFlagAsAccessed(43, "fuseboxNetworkInspectionEnabled");
|
||||
markFlagAsAccessed(42, "fuseboxNetworkInspectionEnabled");
|
||||
|
||||
flagValue = currentProvider_->fuseboxNetworkInspectionEnabled();
|
||||
fuseboxNetworkInspectionEnabled_ = flagValue;
|
||||
@@ -830,7 +812,7 @@ bool ReactNativeFeatureFlagsAccessor::hideOffscreenVirtualViewsOnIOS() {
|
||||
// be accessing the provider multiple times but the end state of this
|
||||
// instance and the returned flag value would be the same.
|
||||
|
||||
markFlagAsAccessed(44, "hideOffscreenVirtualViewsOnIOS");
|
||||
markFlagAsAccessed(43, "hideOffscreenVirtualViewsOnIOS");
|
||||
|
||||
flagValue = currentProvider_->hideOffscreenVirtualViewsOnIOS();
|
||||
hideOffscreenVirtualViewsOnIOS_ = flagValue;
|
||||
@@ -848,7 +830,7 @@ double ReactNativeFeatureFlagsAccessor::preparedTextCacheSize() {
|
||||
// be accessing the provider multiple times but the end state of this
|
||||
// instance and the returned flag value would be the same.
|
||||
|
||||
markFlagAsAccessed(45, "preparedTextCacheSize");
|
||||
markFlagAsAccessed(44, "preparedTextCacheSize");
|
||||
|
||||
flagValue = currentProvider_->preparedTextCacheSize();
|
||||
preparedTextCacheSize_ = flagValue;
|
||||
@@ -857,24 +839,6 @@ double ReactNativeFeatureFlagsAccessor::preparedTextCacheSize() {
|
||||
return flagValue.value();
|
||||
}
|
||||
|
||||
bool ReactNativeFeatureFlagsAccessor::preventShadowTreeCommitExhaustionWithLocking() {
|
||||
auto flagValue = preventShadowTreeCommitExhaustionWithLocking_.load();
|
||||
|
||||
if (!flagValue.has_value()) {
|
||||
// This block is not exclusive but it is not necessary.
|
||||
// If multiple threads try to initialize the feature flag, we would only
|
||||
// be accessing the provider multiple times but the end state of this
|
||||
// instance and the returned flag value would be the same.
|
||||
|
||||
markFlagAsAccessed(46, "preventShadowTreeCommitExhaustionWithLocking");
|
||||
|
||||
flagValue = currentProvider_->preventShadowTreeCommitExhaustionWithLocking();
|
||||
preventShadowTreeCommitExhaustionWithLocking_ = flagValue;
|
||||
}
|
||||
|
||||
return flagValue.value();
|
||||
}
|
||||
|
||||
bool ReactNativeFeatureFlagsAccessor::releaseImageDataWhenConsumed() {
|
||||
auto flagValue = releaseImageDataWhenConsumed_.load();
|
||||
|
||||
@@ -884,7 +848,7 @@ bool ReactNativeFeatureFlagsAccessor::releaseImageDataWhenConsumed() {
|
||||
// be accessing the provider multiple times but the end state of this
|
||||
// instance and the returned flag value would be the same.
|
||||
|
||||
markFlagAsAccessed(47, "releaseImageDataWhenConsumed");
|
||||
markFlagAsAccessed(45, "releaseImageDataWhenConsumed");
|
||||
|
||||
flagValue = currentProvider_->releaseImageDataWhenConsumed();
|
||||
releaseImageDataWhenConsumed_ = flagValue;
|
||||
@@ -893,24 +857,6 @@ bool ReactNativeFeatureFlagsAccessor::releaseImageDataWhenConsumed() {
|
||||
return flagValue.value();
|
||||
}
|
||||
|
||||
bool ReactNativeFeatureFlagsAccessor::skipActivityIdentityAssertionOnHostPause() {
|
||||
auto flagValue = skipActivityIdentityAssertionOnHostPause_.load();
|
||||
|
||||
if (!flagValue.has_value()) {
|
||||
// This block is not exclusive but it is not necessary.
|
||||
// If multiple threads try to initialize the feature flag, we would only
|
||||
// be accessing the provider multiple times but the end state of this
|
||||
// instance and the returned flag value would be the same.
|
||||
|
||||
markFlagAsAccessed(48, "skipActivityIdentityAssertionOnHostPause");
|
||||
|
||||
flagValue = currentProvider_->skipActivityIdentityAssertionOnHostPause();
|
||||
skipActivityIdentityAssertionOnHostPause_ = flagValue;
|
||||
}
|
||||
|
||||
return flagValue.value();
|
||||
}
|
||||
|
||||
bool ReactNativeFeatureFlagsAccessor::traceTurboModulePromiseRejectionsOnAndroid() {
|
||||
auto flagValue = traceTurboModulePromiseRejectionsOnAndroid_.load();
|
||||
|
||||
@@ -920,7 +866,7 @@ bool ReactNativeFeatureFlagsAccessor::traceTurboModulePromiseRejectionsOnAndroid
|
||||
// be accessing the provider multiple times but the end state of this
|
||||
// instance and the returned flag value would be the same.
|
||||
|
||||
markFlagAsAccessed(49, "traceTurboModulePromiseRejectionsOnAndroid");
|
||||
markFlagAsAccessed(46, "traceTurboModulePromiseRejectionsOnAndroid");
|
||||
|
||||
flagValue = currentProvider_->traceTurboModulePromiseRejectionsOnAndroid();
|
||||
traceTurboModulePromiseRejectionsOnAndroid_ = flagValue;
|
||||
@@ -938,7 +884,7 @@ bool ReactNativeFeatureFlagsAccessor::updateRuntimeShadowNodeReferencesOnCommit(
|
||||
// be accessing the provider multiple times but the end state of this
|
||||
// instance and the returned flag value would be the same.
|
||||
|
||||
markFlagAsAccessed(50, "updateRuntimeShadowNodeReferencesOnCommit");
|
||||
markFlagAsAccessed(47, "updateRuntimeShadowNodeReferencesOnCommit");
|
||||
|
||||
flagValue = currentProvider_->updateRuntimeShadowNodeReferencesOnCommit();
|
||||
updateRuntimeShadowNodeReferencesOnCommit_ = flagValue;
|
||||
@@ -956,7 +902,7 @@ bool ReactNativeFeatureFlagsAccessor::useAlwaysAvailableJSErrorHandling() {
|
||||
// be accessing the provider multiple times but the end state of this
|
||||
// instance and the returned flag value would be the same.
|
||||
|
||||
markFlagAsAccessed(51, "useAlwaysAvailableJSErrorHandling");
|
||||
markFlagAsAccessed(48, "useAlwaysAvailableJSErrorHandling");
|
||||
|
||||
flagValue = currentProvider_->useAlwaysAvailableJSErrorHandling();
|
||||
useAlwaysAvailableJSErrorHandling_ = flagValue;
|
||||
@@ -974,7 +920,7 @@ bool ReactNativeFeatureFlagsAccessor::useFabricInterop() {
|
||||
// be accessing the provider multiple times but the end state of this
|
||||
// instance and the returned flag value would be the same.
|
||||
|
||||
markFlagAsAccessed(52, "useFabricInterop");
|
||||
markFlagAsAccessed(49, "useFabricInterop");
|
||||
|
||||
flagValue = currentProvider_->useFabricInterop();
|
||||
useFabricInterop_ = flagValue;
|
||||
@@ -983,42 +929,6 @@ bool ReactNativeFeatureFlagsAccessor::useFabricInterop() {
|
||||
return flagValue.value();
|
||||
}
|
||||
|
||||
bool ReactNativeFeatureFlagsAccessor::useNativeEqualsInNativeReadableArrayAndroid() {
|
||||
auto flagValue = useNativeEqualsInNativeReadableArrayAndroid_.load();
|
||||
|
||||
if (!flagValue.has_value()) {
|
||||
// This block is not exclusive but it is not necessary.
|
||||
// If multiple threads try to initialize the feature flag, we would only
|
||||
// be accessing the provider multiple times but the end state of this
|
||||
// instance and the returned flag value would be the same.
|
||||
|
||||
markFlagAsAccessed(53, "useNativeEqualsInNativeReadableArrayAndroid");
|
||||
|
||||
flagValue = currentProvider_->useNativeEqualsInNativeReadableArrayAndroid();
|
||||
useNativeEqualsInNativeReadableArrayAndroid_ = flagValue;
|
||||
}
|
||||
|
||||
return flagValue.value();
|
||||
}
|
||||
|
||||
bool ReactNativeFeatureFlagsAccessor::useNativeTransformHelperAndroid() {
|
||||
auto flagValue = useNativeTransformHelperAndroid_.load();
|
||||
|
||||
if (!flagValue.has_value()) {
|
||||
// This block is not exclusive but it is not necessary.
|
||||
// If multiple threads try to initialize the feature flag, we would only
|
||||
// be accessing the provider multiple times but the end state of this
|
||||
// instance and the returned flag value would be the same.
|
||||
|
||||
markFlagAsAccessed(54, "useNativeTransformHelperAndroid");
|
||||
|
||||
flagValue = currentProvider_->useNativeTransformHelperAndroid();
|
||||
useNativeTransformHelperAndroid_ = flagValue;
|
||||
}
|
||||
|
||||
return flagValue.value();
|
||||
}
|
||||
|
||||
bool ReactNativeFeatureFlagsAccessor::useNativeViewConfigsInBridgelessMode() {
|
||||
auto flagValue = useNativeViewConfigsInBridgelessMode_.load();
|
||||
|
||||
@@ -1028,7 +938,7 @@ bool ReactNativeFeatureFlagsAccessor::useNativeViewConfigsInBridgelessMode() {
|
||||
// be accessing the provider multiple times but the end state of this
|
||||
// instance and the returned flag value would be the same.
|
||||
|
||||
markFlagAsAccessed(55, "useNativeViewConfigsInBridgelessMode");
|
||||
markFlagAsAccessed(50, "useNativeViewConfigsInBridgelessMode");
|
||||
|
||||
flagValue = currentProvider_->useNativeViewConfigsInBridgelessMode();
|
||||
useNativeViewConfigsInBridgelessMode_ = flagValue;
|
||||
@@ -1046,7 +956,7 @@ bool ReactNativeFeatureFlagsAccessor::useOptimizedEventBatchingOnAndroid() {
|
||||
// be accessing the provider multiple times but the end state of this
|
||||
// instance and the returned flag value would be the same.
|
||||
|
||||
markFlagAsAccessed(56, "useOptimizedEventBatchingOnAndroid");
|
||||
markFlagAsAccessed(51, "useOptimizedEventBatchingOnAndroid");
|
||||
|
||||
flagValue = currentProvider_->useOptimizedEventBatchingOnAndroid();
|
||||
useOptimizedEventBatchingOnAndroid_ = flagValue;
|
||||
@@ -1064,7 +974,7 @@ bool ReactNativeFeatureFlagsAccessor::useRawPropsJsiValue() {
|
||||
// be accessing the provider multiple times but the end state of this
|
||||
// instance and the returned flag value would be the same.
|
||||
|
||||
markFlagAsAccessed(57, "useRawPropsJsiValue");
|
||||
markFlagAsAccessed(52, "useRawPropsJsiValue");
|
||||
|
||||
flagValue = currentProvider_->useRawPropsJsiValue();
|
||||
useRawPropsJsiValue_ = flagValue;
|
||||
@@ -1082,7 +992,7 @@ bool ReactNativeFeatureFlagsAccessor::useShadowNodeStateOnClone() {
|
||||
// be accessing the provider multiple times but the end state of this
|
||||
// instance and the returned flag value would be the same.
|
||||
|
||||
markFlagAsAccessed(58, "useShadowNodeStateOnClone");
|
||||
markFlagAsAccessed(53, "useShadowNodeStateOnClone");
|
||||
|
||||
flagValue = currentProvider_->useShadowNodeStateOnClone();
|
||||
useShadowNodeStateOnClone_ = flagValue;
|
||||
@@ -1100,7 +1010,7 @@ bool ReactNativeFeatureFlagsAccessor::useTurboModuleInterop() {
|
||||
// be accessing the provider multiple times but the end state of this
|
||||
// instance and the returned flag value would be the same.
|
||||
|
||||
markFlagAsAccessed(59, "useTurboModuleInterop");
|
||||
markFlagAsAccessed(54, "useTurboModuleInterop");
|
||||
|
||||
flagValue = currentProvider_->useTurboModuleInterop();
|
||||
useTurboModuleInterop_ = flagValue;
|
||||
@@ -1118,7 +1028,7 @@ bool ReactNativeFeatureFlagsAccessor::useTurboModules() {
|
||||
// be accessing the provider multiple times but the end state of this
|
||||
// instance and the returned flag value would be the same.
|
||||
|
||||
markFlagAsAccessed(60, "useTurboModules");
|
||||
markFlagAsAccessed(55, "useTurboModules");
|
||||
|
||||
flagValue = currentProvider_->useTurboModules();
|
||||
useTurboModules_ = flagValue;
|
||||
@@ -1136,7 +1046,7 @@ double ReactNativeFeatureFlagsAccessor::virtualViewPrerenderRatio() {
|
||||
// be accessing the provider multiple times but the end state of this
|
||||
// instance and the returned flag value would be the same.
|
||||
|
||||
markFlagAsAccessed(61, "virtualViewPrerenderRatio");
|
||||
markFlagAsAccessed(56, "virtualViewPrerenderRatio");
|
||||
|
||||
flagValue = currentProvider_->virtualViewPrerenderRatio();
|
||||
virtualViewPrerenderRatio_ = flagValue;
|
||||
|
||||
+2
-12
@@ -4,7 +4,7 @@
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @generated SignedSource<<edfd880ca5034a683053dc95e177a7c2>>
|
||||
* @generated SignedSource<<7dd91dc5181b06ffb8909245da18c347>>
|
||||
*/
|
||||
|
||||
/**
|
||||
@@ -54,7 +54,6 @@ class ReactNativeFeatureFlagsAccessor {
|
||||
bool enableFontScaleChangesUpdatingLayout();
|
||||
bool enableIOSTextBaselineOffsetPerLine();
|
||||
bool enableIOSViewClipToPaddingBox();
|
||||
bool enableImmediateUpdateModeForContentOffsetChanges();
|
||||
bool enableInteropViewManagerClassLookUpOptimizationIOS();
|
||||
bool enableLayoutAnimationsOnAndroid();
|
||||
bool enableLayoutAnimationsOnIOS();
|
||||
@@ -78,15 +77,11 @@ class ReactNativeFeatureFlagsAccessor {
|
||||
bool fuseboxNetworkInspectionEnabled();
|
||||
bool hideOffscreenVirtualViewsOnIOS();
|
||||
double preparedTextCacheSize();
|
||||
bool preventShadowTreeCommitExhaustionWithLocking();
|
||||
bool releaseImageDataWhenConsumed();
|
||||
bool skipActivityIdentityAssertionOnHostPause();
|
||||
bool traceTurboModulePromiseRejectionsOnAndroid();
|
||||
bool updateRuntimeShadowNodeReferencesOnCommit();
|
||||
bool useAlwaysAvailableJSErrorHandling();
|
||||
bool useFabricInterop();
|
||||
bool useNativeEqualsInNativeReadableArrayAndroid();
|
||||
bool useNativeTransformHelperAndroid();
|
||||
bool useNativeViewConfigsInBridgelessMode();
|
||||
bool useOptimizedEventBatchingOnAndroid();
|
||||
bool useRawPropsJsiValue();
|
||||
@@ -105,7 +100,7 @@ class ReactNativeFeatureFlagsAccessor {
|
||||
std::unique_ptr<ReactNativeFeatureFlagsProvider> currentProvider_;
|
||||
bool wasOverridden_;
|
||||
|
||||
std::array<std::atomic<const char*>, 62> accessedFeatureFlags_;
|
||||
std::array<std::atomic<const char*>, 57> accessedFeatureFlags_;
|
||||
|
||||
std::atomic<std::optional<bool>> commonTestFlag_;
|
||||
std::atomic<std::optional<bool>> cxxNativeAnimatedEnabled_;
|
||||
@@ -129,7 +124,6 @@ class ReactNativeFeatureFlagsAccessor {
|
||||
std::atomic<std::optional<bool>> enableFontScaleChangesUpdatingLayout_;
|
||||
std::atomic<std::optional<bool>> enableIOSTextBaselineOffsetPerLine_;
|
||||
std::atomic<std::optional<bool>> enableIOSViewClipToPaddingBox_;
|
||||
std::atomic<std::optional<bool>> enableImmediateUpdateModeForContentOffsetChanges_;
|
||||
std::atomic<std::optional<bool>> enableInteropViewManagerClassLookUpOptimizationIOS_;
|
||||
std::atomic<std::optional<bool>> enableLayoutAnimationsOnAndroid_;
|
||||
std::atomic<std::optional<bool>> enableLayoutAnimationsOnIOS_;
|
||||
@@ -153,15 +147,11 @@ class ReactNativeFeatureFlagsAccessor {
|
||||
std::atomic<std::optional<bool>> fuseboxNetworkInspectionEnabled_;
|
||||
std::atomic<std::optional<bool>> hideOffscreenVirtualViewsOnIOS_;
|
||||
std::atomic<std::optional<double>> preparedTextCacheSize_;
|
||||
std::atomic<std::optional<bool>> preventShadowTreeCommitExhaustionWithLocking_;
|
||||
std::atomic<std::optional<bool>> releaseImageDataWhenConsumed_;
|
||||
std::atomic<std::optional<bool>> skipActivityIdentityAssertionOnHostPause_;
|
||||
std::atomic<std::optional<bool>> traceTurboModulePromiseRejectionsOnAndroid_;
|
||||
std::atomic<std::optional<bool>> updateRuntimeShadowNodeReferencesOnCommit_;
|
||||
std::atomic<std::optional<bool>> useAlwaysAvailableJSErrorHandling_;
|
||||
std::atomic<std::optional<bool>> useFabricInterop_;
|
||||
std::atomic<std::optional<bool>> useNativeEqualsInNativeReadableArrayAndroid_;
|
||||
std::atomic<std::optional<bool>> useNativeTransformHelperAndroid_;
|
||||
std::atomic<std::optional<bool>> useNativeViewConfigsInBridgelessMode_;
|
||||
std::atomic<std::optional<bool>> useOptimizedEventBatchingOnAndroid_;
|
||||
std::atomic<std::optional<bool>> useRawPropsJsiValue_;
|
||||
|
||||
+2
-22
@@ -4,7 +4,7 @@
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @generated SignedSource<<614fe0894f6235d879a0b29e7dab7759>>
|
||||
* @generated SignedSource<<64cac29f0902d801e8a7e1d2ab17ddd5>>
|
||||
*/
|
||||
|
||||
/**
|
||||
@@ -115,10 +115,6 @@ class ReactNativeFeatureFlagsDefaults : public ReactNativeFeatureFlagsProvider {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool enableImmediateUpdateModeForContentOffsetChanges() override {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool enableInteropViewManagerClassLookUpOptimizationIOS() override {
|
||||
return false;
|
||||
}
|
||||
@@ -184,7 +180,7 @@ class ReactNativeFeatureFlagsDefaults : public ReactNativeFeatureFlagsProvider {
|
||||
}
|
||||
|
||||
bool enableVirtualViewRenderState() override {
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool enableVirtualViewWindowFocusDetection() override {
|
||||
@@ -211,18 +207,10 @@ class ReactNativeFeatureFlagsDefaults : public ReactNativeFeatureFlagsProvider {
|
||||
return 200.0;
|
||||
}
|
||||
|
||||
bool preventShadowTreeCommitExhaustionWithLocking() override {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool releaseImageDataWhenConsumed() override {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool skipActivityIdentityAssertionOnHostPause() override {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool traceTurboModulePromiseRejectionsOnAndroid() override {
|
||||
return false;
|
||||
}
|
||||
@@ -239,14 +227,6 @@ class ReactNativeFeatureFlagsDefaults : public ReactNativeFeatureFlagsProvider {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool useNativeEqualsInNativeReadableArrayAndroid() override {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool useNativeTransformHelperAndroid() override {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool useNativeViewConfigsInBridgelessMode() override {
|
||||
return false;
|
||||
}
|
||||
|
||||
+1
-46
@@ -4,7 +4,7 @@
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @generated SignedSource<<6502c090532e1d7d2ac67cf6e711d9f4>>
|
||||
* @generated SignedSource<<d8c2161445fd7dead9c4d3444b3c9065>>
|
||||
*/
|
||||
|
||||
/**
|
||||
@@ -243,15 +243,6 @@ class ReactNativeFeatureFlagsDynamicProvider : public ReactNativeFeatureFlagsDef
|
||||
return ReactNativeFeatureFlagsDefaults::enableIOSViewClipToPaddingBox();
|
||||
}
|
||||
|
||||
bool enableImmediateUpdateModeForContentOffsetChanges() override {
|
||||
auto value = values_["enableImmediateUpdateModeForContentOffsetChanges"];
|
||||
if (!value.isNull()) {
|
||||
return value.getBool();
|
||||
}
|
||||
|
||||
return ReactNativeFeatureFlagsDefaults::enableImmediateUpdateModeForContentOffsetChanges();
|
||||
}
|
||||
|
||||
bool enableInteropViewManagerClassLookUpOptimizationIOS() override {
|
||||
auto value = values_["enableInteropViewManagerClassLookUpOptimizationIOS"];
|
||||
if (!value.isNull()) {
|
||||
@@ -459,15 +450,6 @@ class ReactNativeFeatureFlagsDynamicProvider : public ReactNativeFeatureFlagsDef
|
||||
return ReactNativeFeatureFlagsDefaults::preparedTextCacheSize();
|
||||
}
|
||||
|
||||
bool preventShadowTreeCommitExhaustionWithLocking() override {
|
||||
auto value = values_["preventShadowTreeCommitExhaustionWithLocking"];
|
||||
if (!value.isNull()) {
|
||||
return value.getBool();
|
||||
}
|
||||
|
||||
return ReactNativeFeatureFlagsDefaults::preventShadowTreeCommitExhaustionWithLocking();
|
||||
}
|
||||
|
||||
bool releaseImageDataWhenConsumed() override {
|
||||
auto value = values_["releaseImageDataWhenConsumed"];
|
||||
if (!value.isNull()) {
|
||||
@@ -477,15 +459,6 @@ class ReactNativeFeatureFlagsDynamicProvider : public ReactNativeFeatureFlagsDef
|
||||
return ReactNativeFeatureFlagsDefaults::releaseImageDataWhenConsumed();
|
||||
}
|
||||
|
||||
bool skipActivityIdentityAssertionOnHostPause() override {
|
||||
auto value = values_["skipActivityIdentityAssertionOnHostPause"];
|
||||
if (!value.isNull()) {
|
||||
return value.getBool();
|
||||
}
|
||||
|
||||
return ReactNativeFeatureFlagsDefaults::skipActivityIdentityAssertionOnHostPause();
|
||||
}
|
||||
|
||||
bool traceTurboModulePromiseRejectionsOnAndroid() override {
|
||||
auto value = values_["traceTurboModulePromiseRejectionsOnAndroid"];
|
||||
if (!value.isNull()) {
|
||||
@@ -522,24 +495,6 @@ class ReactNativeFeatureFlagsDynamicProvider : public ReactNativeFeatureFlagsDef
|
||||
return ReactNativeFeatureFlagsDefaults::useFabricInterop();
|
||||
}
|
||||
|
||||
bool useNativeEqualsInNativeReadableArrayAndroid() override {
|
||||
auto value = values_["useNativeEqualsInNativeReadableArrayAndroid"];
|
||||
if (!value.isNull()) {
|
||||
return value.getBool();
|
||||
}
|
||||
|
||||
return ReactNativeFeatureFlagsDefaults::useNativeEqualsInNativeReadableArrayAndroid();
|
||||
}
|
||||
|
||||
bool useNativeTransformHelperAndroid() override {
|
||||
auto value = values_["useNativeTransformHelperAndroid"];
|
||||
if (!value.isNull()) {
|
||||
return value.getBool();
|
||||
}
|
||||
|
||||
return ReactNativeFeatureFlagsDefaults::useNativeTransformHelperAndroid();
|
||||
}
|
||||
|
||||
bool useNativeViewConfigsInBridgelessMode() override {
|
||||
auto value = values_["useNativeViewConfigsInBridgelessMode"];
|
||||
if (!value.isNull()) {
|
||||
|
||||
+1
-6
@@ -4,7 +4,7 @@
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @generated SignedSource<<a26af781141939d35cff83bacf522bb0>>
|
||||
* @generated SignedSource<<d759f36e6b262bbcbd7bbdabece76042>>
|
||||
*/
|
||||
|
||||
/**
|
||||
@@ -47,7 +47,6 @@ class ReactNativeFeatureFlagsProvider {
|
||||
virtual bool enableFontScaleChangesUpdatingLayout() = 0;
|
||||
virtual bool enableIOSTextBaselineOffsetPerLine() = 0;
|
||||
virtual bool enableIOSViewClipToPaddingBox() = 0;
|
||||
virtual bool enableImmediateUpdateModeForContentOffsetChanges() = 0;
|
||||
virtual bool enableInteropViewManagerClassLookUpOptimizationIOS() = 0;
|
||||
virtual bool enableLayoutAnimationsOnAndroid() = 0;
|
||||
virtual bool enableLayoutAnimationsOnIOS() = 0;
|
||||
@@ -71,15 +70,11 @@ class ReactNativeFeatureFlagsProvider {
|
||||
virtual bool fuseboxNetworkInspectionEnabled() = 0;
|
||||
virtual bool hideOffscreenVirtualViewsOnIOS() = 0;
|
||||
virtual double preparedTextCacheSize() = 0;
|
||||
virtual bool preventShadowTreeCommitExhaustionWithLocking() = 0;
|
||||
virtual bool releaseImageDataWhenConsumed() = 0;
|
||||
virtual bool skipActivityIdentityAssertionOnHostPause() = 0;
|
||||
virtual bool traceTurboModulePromiseRejectionsOnAndroid() = 0;
|
||||
virtual bool updateRuntimeShadowNodeReferencesOnCommit() = 0;
|
||||
virtual bool useAlwaysAvailableJSErrorHandling() = 0;
|
||||
virtual bool useFabricInterop() = 0;
|
||||
virtual bool useNativeEqualsInNativeReadableArrayAndroid() = 0;
|
||||
virtual bool useNativeTransformHelperAndroid() = 0;
|
||||
virtual bool useNativeViewConfigsInBridgelessMode() = 0;
|
||||
virtual bool useOptimizedEventBatchingOnAndroid() = 0;
|
||||
virtual bool useRawPropsJsiValue() = 0;
|
||||
|
||||
+1
-26
@@ -4,7 +4,7 @@
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @generated SignedSource<<cadb1f2c1c10a03593dc7c9a9a94747b>>
|
||||
* @generated SignedSource<<3bb595d448d15f55ded8e5ddc4549bcb>>
|
||||
*/
|
||||
|
||||
/**
|
||||
@@ -154,11 +154,6 @@ bool NativeReactNativeFeatureFlags::enableIOSViewClipToPaddingBox(
|
||||
return ReactNativeFeatureFlags::enableIOSViewClipToPaddingBox();
|
||||
}
|
||||
|
||||
bool NativeReactNativeFeatureFlags::enableImmediateUpdateModeForContentOffsetChanges(
|
||||
jsi::Runtime& /*runtime*/) {
|
||||
return ReactNativeFeatureFlags::enableImmediateUpdateModeForContentOffsetChanges();
|
||||
}
|
||||
|
||||
bool NativeReactNativeFeatureFlags::enableInteropViewManagerClassLookUpOptimizationIOS(
|
||||
jsi::Runtime& /*runtime*/) {
|
||||
return ReactNativeFeatureFlags::enableInteropViewManagerClassLookUpOptimizationIOS();
|
||||
@@ -274,21 +269,11 @@ double NativeReactNativeFeatureFlags::preparedTextCacheSize(
|
||||
return ReactNativeFeatureFlags::preparedTextCacheSize();
|
||||
}
|
||||
|
||||
bool NativeReactNativeFeatureFlags::preventShadowTreeCommitExhaustionWithLocking(
|
||||
jsi::Runtime& /*runtime*/) {
|
||||
return ReactNativeFeatureFlags::preventShadowTreeCommitExhaustionWithLocking();
|
||||
}
|
||||
|
||||
bool NativeReactNativeFeatureFlags::releaseImageDataWhenConsumed(
|
||||
jsi::Runtime& /*runtime*/) {
|
||||
return ReactNativeFeatureFlags::releaseImageDataWhenConsumed();
|
||||
}
|
||||
|
||||
bool NativeReactNativeFeatureFlags::skipActivityIdentityAssertionOnHostPause(
|
||||
jsi::Runtime& /*runtime*/) {
|
||||
return ReactNativeFeatureFlags::skipActivityIdentityAssertionOnHostPause();
|
||||
}
|
||||
|
||||
bool NativeReactNativeFeatureFlags::traceTurboModulePromiseRejectionsOnAndroid(
|
||||
jsi::Runtime& /*runtime*/) {
|
||||
return ReactNativeFeatureFlags::traceTurboModulePromiseRejectionsOnAndroid();
|
||||
@@ -309,16 +294,6 @@ bool NativeReactNativeFeatureFlags::useFabricInterop(
|
||||
return ReactNativeFeatureFlags::useFabricInterop();
|
||||
}
|
||||
|
||||
bool NativeReactNativeFeatureFlags::useNativeEqualsInNativeReadableArrayAndroid(
|
||||
jsi::Runtime& /*runtime*/) {
|
||||
return ReactNativeFeatureFlags::useNativeEqualsInNativeReadableArrayAndroid();
|
||||
}
|
||||
|
||||
bool NativeReactNativeFeatureFlags::useNativeTransformHelperAndroid(
|
||||
jsi::Runtime& /*runtime*/) {
|
||||
return ReactNativeFeatureFlags::useNativeTransformHelperAndroid();
|
||||
}
|
||||
|
||||
bool NativeReactNativeFeatureFlags::useNativeViewConfigsInBridgelessMode(
|
||||
jsi::Runtime& /*runtime*/) {
|
||||
return ReactNativeFeatureFlags::useNativeViewConfigsInBridgelessMode();
|
||||
|
||||
+1
-11
@@ -4,7 +4,7 @@
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @generated SignedSource<<de04d72490f2c09abdcea51e6f02796c>>
|
||||
* @generated SignedSource<<130929d2cc38d298a27dd6afc5c746ca>>
|
||||
*/
|
||||
|
||||
/**
|
||||
@@ -80,8 +80,6 @@ class NativeReactNativeFeatureFlags
|
||||
|
||||
bool enableIOSViewClipToPaddingBox(jsi::Runtime& runtime);
|
||||
|
||||
bool enableImmediateUpdateModeForContentOffsetChanges(jsi::Runtime& runtime);
|
||||
|
||||
bool enableInteropViewManagerClassLookUpOptimizationIOS(jsi::Runtime& runtime);
|
||||
|
||||
bool enableLayoutAnimationsOnAndroid(jsi::Runtime& runtime);
|
||||
@@ -128,12 +126,8 @@ class NativeReactNativeFeatureFlags
|
||||
|
||||
double preparedTextCacheSize(jsi::Runtime& runtime);
|
||||
|
||||
bool preventShadowTreeCommitExhaustionWithLocking(jsi::Runtime& runtime);
|
||||
|
||||
bool releaseImageDataWhenConsumed(jsi::Runtime& runtime);
|
||||
|
||||
bool skipActivityIdentityAssertionOnHostPause(jsi::Runtime& runtime);
|
||||
|
||||
bool traceTurboModulePromiseRejectionsOnAndroid(jsi::Runtime& runtime);
|
||||
|
||||
bool updateRuntimeShadowNodeReferencesOnCommit(jsi::Runtime& runtime);
|
||||
@@ -142,10 +136,6 @@ class NativeReactNativeFeatureFlags
|
||||
|
||||
bool useFabricInterop(jsi::Runtime& runtime);
|
||||
|
||||
bool useNativeEqualsInNativeReadableArrayAndroid(jsi::Runtime& runtime);
|
||||
|
||||
bool useNativeTransformHelperAndroid(jsi::Runtime& runtime);
|
||||
|
||||
bool useNativeViewConfigsInBridgelessMode(jsi::Runtime& runtime);
|
||||
|
||||
bool useOptimizedEventBatchingOnAndroid(jsi::Runtime& runtime);
|
||||
|
||||
+15
@@ -49,6 +49,21 @@ NativeIntersectionObserver::NativeIntersectionObserver(
|
||||
std::shared_ptr<CallInvoker> jsInvoker)
|
||||
: NativeIntersectionObserverCxxSpec(std::move(jsInvoker)) {}
|
||||
|
||||
void NativeIntersectionObserver::observe(
|
||||
jsi::Runtime& runtime,
|
||||
NativeIntersectionObserverObserveOptions options) {
|
||||
observeV2(runtime, std::move(options));
|
||||
}
|
||||
|
||||
void NativeIntersectionObserver::unobserve(
|
||||
jsi::Runtime& runtime,
|
||||
IntersectionObserverObserverId intersectionObserverId,
|
||||
std::shared_ptr<const ShadowNode> targetShadowNode) {
|
||||
auto token =
|
||||
tokenFromShadowNodeFamily(runtime, targetShadowNode->getFamilyShared());
|
||||
unobserveV2(runtime, intersectionObserverId, std::move(token));
|
||||
}
|
||||
|
||||
jsi::Object NativeIntersectionObserver::observeV2(
|
||||
jsi::Runtime& runtime,
|
||||
NativeIntersectionObserverObserveOptions options) {
|
||||
|
||||
+13
@@ -64,6 +64,19 @@ class NativeIntersectionObserver
|
||||
public:
|
||||
NativeIntersectionObserver(std::shared_ptr<CallInvoker> jsInvoker);
|
||||
|
||||
// TODO(T223605846): Remove legacy observe method
|
||||
[[deprecated("Please use observeV2")]]
|
||||
void observe(
|
||||
jsi::Runtime& runtime,
|
||||
NativeIntersectionObserverObserveOptions options);
|
||||
|
||||
// TODO(T223605846): Remove legacy unobserve method
|
||||
[[deprecated("Please use unobserveV2")]]
|
||||
void unobserve(
|
||||
jsi::Runtime& runtime,
|
||||
IntersectionObserverObserverId intersectionObserverId,
|
||||
std::shared_ptr<const ShadowNode> targetShadowNode);
|
||||
|
||||
jsi::Object observeV2(
|
||||
jsi::Runtime& runtime,
|
||||
NativeIntersectionObserverObserveOptions options);
|
||||
|
||||
+95
-32
@@ -13,7 +13,6 @@
|
||||
|
||||
#include <cxxreact/JSExecutor.h>
|
||||
#include <cxxreact/ReactMarker.h>
|
||||
#include <jsi/JSIDynamic.h>
|
||||
#include <jsi/instrumentation.h>
|
||||
#include <react/performance/timeline/PerformanceEntryReporter.h>
|
||||
#include <react/performance/timeline/PerformanceObserver.h>
|
||||
@@ -112,19 +111,6 @@ std::shared_ptr<PerformanceObserver> tryGetObserver(
|
||||
return observerWrapper ? observerWrapper->observer : nullptr;
|
||||
}
|
||||
|
||||
PerformanceEntryReporter::UserTimingDetailProvider getDetailProviderFromEntry(
|
||||
jsi::Runtime& rt,
|
||||
jsi::Value& entry) {
|
||||
return [&rt, &entry]() -> folly::dynamic {
|
||||
try {
|
||||
auto detail = entry.asObject(rt).getProperty(rt, "detail");
|
||||
return jsi::dynamicFromValue(rt, detail);
|
||||
} catch (jsi::JSIException& ex) {
|
||||
return nullptr;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
NativePerformance::NativePerformance(std::shared_ptr<CallInvoker> jsInvoker)
|
||||
@@ -134,31 +120,108 @@ HighResTimeStamp NativePerformance::now(jsi::Runtime& /*rt*/) {
|
||||
return forcedCurrentTimeStamp_.value_or(HighResTimeStamp::now());
|
||||
}
|
||||
|
||||
void NativePerformance::reportMark(
|
||||
HighResTimeStamp NativePerformance::markWithResult(
|
||||
jsi::Runtime& rt,
|
||||
std::string name,
|
||||
HighResTimeStamp startTime,
|
||||
jsi::Value entry) {
|
||||
PerformanceEntryReporter::getInstance()->reportMark(
|
||||
name, startTime, getDetailProviderFromEntry(rt, entry));
|
||||
std::optional<HighResTimeStamp> startTime) {
|
||||
auto entry = PerformanceEntryReporter::getInstance()->reportMark(
|
||||
name, startTime.value_or(now(rt)));
|
||||
return entry.startTime;
|
||||
}
|
||||
|
||||
void NativePerformance::reportMeasure(
|
||||
jsi::Runtime& rt,
|
||||
std::tuple<HighResTimeStamp, HighResDuration> NativePerformance::measure(
|
||||
jsi::Runtime& runtime,
|
||||
std::string name,
|
||||
std::optional<HighResTimeStamp> startTime,
|
||||
std::optional<HighResTimeStamp> endTime,
|
||||
std::optional<HighResDuration> duration,
|
||||
std::optional<std::string> startMark,
|
||||
std::optional<std::string> endMark) {
|
||||
auto reporter = PerformanceEntryReporter::getInstance();
|
||||
|
||||
HighResTimeStamp startTimeValue;
|
||||
|
||||
// If the start time mark name is specified, it takes precedence over the
|
||||
// startTime parameter, which can be set to 0 by default from JavaScript.
|
||||
if (startTime) {
|
||||
startTimeValue = *startTime;
|
||||
} else if (startMark) {
|
||||
if (auto startMarkBufferedTime = reporter->getMarkTime(*startMark)) {
|
||||
startTimeValue = *startMarkBufferedTime;
|
||||
} else {
|
||||
throw jsi::JSError(
|
||||
runtime, "The mark '" + *startMark + "' does not exist.");
|
||||
}
|
||||
} else {
|
||||
startTimeValue = HighResTimeStamp::fromDOMHighResTimeStamp(0);
|
||||
}
|
||||
|
||||
HighResTimeStamp endTimeValue;
|
||||
|
||||
if (endTime) {
|
||||
endTimeValue = *endTime;
|
||||
} else if (duration) {
|
||||
endTimeValue = startTimeValue + *duration;
|
||||
} else if (endMark) {
|
||||
if (auto endMarkBufferedTime = reporter->getMarkTime(*endMark)) {
|
||||
endTimeValue = *endMarkBufferedTime;
|
||||
} else {
|
||||
throw jsi::JSError(
|
||||
runtime, "The mark '" + *endMark + "' does not exist.");
|
||||
}
|
||||
} else {
|
||||
// The end time is not specified, take the current time, according to the
|
||||
// standard
|
||||
endTimeValue = now(runtime);
|
||||
}
|
||||
|
||||
auto entry = reporter->reportMeasure(name, startTimeValue, endTimeValue);
|
||||
return std::tuple{entry.startTime, entry.duration};
|
||||
}
|
||||
|
||||
std::tuple<HighResTimeStamp, HighResDuration>
|
||||
NativePerformance::measureWithResult(
|
||||
jsi::Runtime& runtime,
|
||||
std::string name,
|
||||
HighResTimeStamp startTime,
|
||||
HighResDuration duration,
|
||||
jsi::Value entry) {
|
||||
PerformanceEntryReporter::getInstance()->reportMeasure(
|
||||
name, startTime, duration, getDetailProviderFromEntry(rt, entry));
|
||||
}
|
||||
HighResTimeStamp endTime,
|
||||
std::optional<HighResDuration> duration,
|
||||
std::optional<std::string> startMark,
|
||||
std::optional<std::string> endMark) {
|
||||
auto reporter = PerformanceEntryReporter::getInstance();
|
||||
|
||||
std::optional<double> NativePerformance::getMarkTime(
|
||||
jsi::Runtime& rt,
|
||||
std::string name) {
|
||||
auto markTime = PerformanceEntryReporter::getInstance()->getMarkTime(name);
|
||||
return markTime ? std::optional{(*markTime).toDOMHighResTimeStamp()}
|
||||
: std::nullopt;
|
||||
HighResTimeStamp startTimeValue = startTime;
|
||||
// If the start time mark name is specified, it takes precedence over the
|
||||
// startTime parameter, which can be set to 0 by default from JavaScript.
|
||||
if (startMark) {
|
||||
if (auto startMarkBufferedTime = reporter->getMarkTime(*startMark)) {
|
||||
startTimeValue = *startMarkBufferedTime;
|
||||
} else {
|
||||
throw jsi::JSError(
|
||||
runtime, "The mark '" + *startMark + "' does not exist.");
|
||||
}
|
||||
}
|
||||
|
||||
HighResTimeStamp endTimeValue = endTime;
|
||||
// If the end time mark name is specified, it takes precedence over the
|
||||
// startTime parameter, which can be set to 0 by default from JavaScript.
|
||||
if (endMark) {
|
||||
if (auto endMarkBufferedTime = reporter->getMarkTime(*endMark)) {
|
||||
endTimeValue = *endMarkBufferedTime;
|
||||
} else {
|
||||
throw jsi::JSError(
|
||||
runtime, "The mark '" + *endMark + "' does not exist.");
|
||||
}
|
||||
} else if (duration) {
|
||||
endTimeValue = startTimeValue + *duration;
|
||||
} else if (endTimeValue < startTimeValue) {
|
||||
// The end time is not specified, take the current time, according to the
|
||||
// standard
|
||||
endTimeValue = now(runtime);
|
||||
}
|
||||
|
||||
auto entry = reporter->reportMeasure(name, startTime, endTime);
|
||||
return std::tuple{entry.startTime, entry.duration};
|
||||
}
|
||||
|
||||
void NativePerformance::clearMarks(
|
||||
|
||||
+20
-8
@@ -90,20 +90,32 @@ class NativePerformance : public NativePerformanceCxxSpec<NativePerformance> {
|
||||
|
||||
#pragma mark - User Timing Level 3 functions (https://w3c.github.io/user-timing/)
|
||||
|
||||
void reportMark(
|
||||
// https://w3c.github.io/user-timing/#mark-method
|
||||
HighResTimeStamp markWithResult(
|
||||
jsi::Runtime& rt,
|
||||
std::string name,
|
||||
HighResTimeStamp time,
|
||||
jsi::Value entry);
|
||||
std::optional<HighResTimeStamp> startTime);
|
||||
|
||||
void reportMeasure(
|
||||
// https://w3c.github.io/user-timing/#measure-method
|
||||
std::tuple<HighResTimeStamp, HighResDuration> measure(
|
||||
jsi::Runtime& rt,
|
||||
std::string name,
|
||||
std::optional<HighResTimeStamp> startTime,
|
||||
std::optional<HighResTimeStamp> endTime,
|
||||
std::optional<HighResDuration> duration,
|
||||
std::optional<std::string> startMark,
|
||||
std::optional<std::string> endMark);
|
||||
|
||||
// https://w3c.github.io/user-timing/#measure-method
|
||||
[[deprecated("This method is deprecated. Use the measure method instead.")]]
|
||||
std::tuple<HighResTimeStamp, HighResDuration> measureWithResult(
|
||||
jsi::Runtime& rt,
|
||||
std::string name,
|
||||
HighResTimeStamp startTime,
|
||||
HighResDuration duration,
|
||||
jsi::Value entry);
|
||||
|
||||
std::optional<double> getMarkTime(jsi::Runtime& rt, std::string name);
|
||||
HighResTimeStamp endTime,
|
||||
std::optional<HighResDuration> duration,
|
||||
std::optional<std::string> startMark,
|
||||
std::optional<std::string> endMark);
|
||||
|
||||
// https://w3c.github.io/user-timing/#clearmarks-method
|
||||
void clearMarks(
|
||||
|
||||
@@ -19,5 +19,4 @@ target_link_libraries(react_performance_timeline
|
||||
jsinspector_tracing
|
||||
reactperflogger
|
||||
react_featureflags
|
||||
react_timing
|
||||
folly_runtime)
|
||||
react_timing)
|
||||
|
||||
+65
-63
@@ -37,40 +37,31 @@ std::vector<PerformanceEntryType> getSupportedEntryTypesInternal() {
|
||||
return supportedEntryTypes;
|
||||
}
|
||||
|
||||
std::optional<std::string> getTrackFromDetail(folly::dynamic& detail) {
|
||||
if (!detail.isObject()) {
|
||||
return std::nullopt;
|
||||
#if defined(__clang__)
|
||||
#define NO_DESTROY [[clang::no_destroy]]
|
||||
#else
|
||||
#define NO_DESTROY
|
||||
#endif
|
||||
|
||||
NO_DESTROY const std::string TRACK_PREFIX = "Track:";
|
||||
|
||||
std::tuple<std::optional<std::string>, std::string_view> parseTrackName(
|
||||
const std::string& name) {
|
||||
// Until there's a standard way to pass through track information, parse it
|
||||
// manually, e.g., "Track:Foo:Event name"
|
||||
// https://github.com/w3c/user-timing/issues/109
|
||||
std::optional<std::string> trackName;
|
||||
std::string_view eventName(name);
|
||||
if (name.starts_with(TRACK_PREFIX)) {
|
||||
const auto trackNameDelimiter = name.find(':', TRACK_PREFIX.length());
|
||||
if (trackNameDelimiter != std::string::npos) {
|
||||
trackName = name.substr(
|
||||
TRACK_PREFIX.length(), trackNameDelimiter - TRACK_PREFIX.length());
|
||||
eventName = std::string_view(name).substr(trackNameDelimiter + 1);
|
||||
}
|
||||
}
|
||||
|
||||
auto maybeDevtools = detail["devtools"];
|
||||
if (!maybeDevtools.isObject()) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
auto maybeTrack = maybeDevtools["track"];
|
||||
if (!maybeTrack.isString()) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
return maybeTrack.asString();
|
||||
}
|
||||
|
||||
std::optional<std::string> getTrackGroupFromDetail(folly::dynamic& detail) {
|
||||
if (!detail.isObject()) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
auto maybeDevtools = detail["devtools"];
|
||||
if (!maybeDevtools.isObject()) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
auto maybeTrackGroup = maybeDevtools["trackGroup"];
|
||||
if (!maybeTrackGroup.isString()) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
return maybeTrackGroup.asString();
|
||||
return std::make_tuple(trackName, eventName);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
@@ -176,13 +167,14 @@ void PerformanceEntryReporter::clearEntries(
|
||||
getBufferRef(entryType).clear(entryName);
|
||||
}
|
||||
|
||||
void PerformanceEntryReporter::reportMark(
|
||||
PerformanceMark PerformanceEntryReporter::reportMark(
|
||||
const std::string& name,
|
||||
const HighResTimeStamp startTime,
|
||||
UserTimingDetailProvider&& detailProvider) {
|
||||
const auto entry = PerformanceMark{{.name = name, .startTime = startTime}};
|
||||
const std::optional<HighResTimeStamp>& startTime) {
|
||||
// Resolve timings
|
||||
auto startTimeVal = startTime ? *startTime : getCurrentTimeStamp();
|
||||
const auto entry = PerformanceMark{{.name = name, .startTime = startTimeVal}};
|
||||
|
||||
traceMark(entry, std::move(detailProvider));
|
||||
traceMark(entry);
|
||||
|
||||
// Add to buffers & notify observers
|
||||
{
|
||||
@@ -191,19 +183,24 @@ void PerformanceEntryReporter::reportMark(
|
||||
}
|
||||
|
||||
observerRegistry_->queuePerformanceEntry(entry);
|
||||
|
||||
return entry;
|
||||
}
|
||||
|
||||
void PerformanceEntryReporter::reportMeasure(
|
||||
PerformanceMeasure PerformanceEntryReporter::reportMeasure(
|
||||
const std::string& name,
|
||||
HighResTimeStamp startTime,
|
||||
HighResDuration duration,
|
||||
UserTimingDetailProvider&& detailProvider) {
|
||||
HighResTimeStamp endTime,
|
||||
const std::optional<jsinspector_modern::DevToolsTrackEntryPayload>&
|
||||
trackMetadata) {
|
||||
HighResDuration duration = endTime - startTime;
|
||||
|
||||
const auto entry = PerformanceMeasure{
|
||||
{.name = std::string(name),
|
||||
.startTime = startTime,
|
||||
.duration = duration}};
|
||||
|
||||
traceMeasure(entry, std::move(detailProvider));
|
||||
traceMeasure(entry);
|
||||
|
||||
// Add to buffers & notify observers
|
||||
{
|
||||
@@ -212,6 +209,8 @@ void PerformanceEntryReporter::reportMeasure(
|
||||
}
|
||||
|
||||
observerRegistry_->queuePerformanceEntry(entry);
|
||||
|
||||
return entry;
|
||||
}
|
||||
|
||||
void PerformanceEntryReporter::clearEventCounts() {
|
||||
@@ -276,7 +275,7 @@ void PerformanceEntryReporter::reportLongTask(
|
||||
observerRegistry_->queuePerformanceEntry(entry);
|
||||
}
|
||||
|
||||
void PerformanceEntryReporter::reportResourceTiming(
|
||||
PerformanceResourceTiming PerformanceEntryReporter::reportResourceTiming(
|
||||
const std::string& url,
|
||||
HighResTimeStamp fetchStart,
|
||||
HighResTimeStamp requestStart,
|
||||
@@ -303,47 +302,50 @@ void PerformanceEntryReporter::reportResourceTiming(
|
||||
}
|
||||
|
||||
observerRegistry_->queuePerformanceEntry(entry);
|
||||
|
||||
return entry;
|
||||
}
|
||||
|
||||
void PerformanceEntryReporter::traceMark(
|
||||
const PerformanceMark& entry,
|
||||
UserTimingDetailProvider&& detailProvider) const {
|
||||
void PerformanceEntryReporter::traceMark(const PerformanceMark& entry) const {
|
||||
auto& performanceTracer =
|
||||
jsinspector_modern::tracing::PerformanceTracer::getInstance();
|
||||
if (ReactPerfettoLogger::isTracing() || performanceTracer.isTracing()) {
|
||||
if (ReactPerfettoLogger::isTracing()) {
|
||||
ReactPerfettoLogger::mark(entry.name, entry.startTime);
|
||||
}
|
||||
auto [trackName, eventName] = parseTrackName(entry.name);
|
||||
|
||||
if (performanceTracer.isTracing()) {
|
||||
performanceTracer.reportMark(
|
||||
entry.name,
|
||||
entry.startTime,
|
||||
detailProvider != nullptr ? detailProvider() : nullptr);
|
||||
performanceTracer.reportMark(entry.name, entry.startTime);
|
||||
}
|
||||
|
||||
if (ReactPerfettoLogger::isTracing()) {
|
||||
ReactPerfettoLogger::mark(eventName, entry.startTime, trackName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PerformanceEntryReporter::traceMeasure(
|
||||
const PerformanceMeasure& entry,
|
||||
UserTimingDetailProvider&& detailProvider) const {
|
||||
const PerformanceMeasure& entry) const {
|
||||
auto& performanceTracer =
|
||||
jsinspector_modern::tracing::PerformanceTracer::getInstance();
|
||||
if (performanceTracer.isTracing() || ReactPerfettoLogger::isTracing()) {
|
||||
auto detail = detailProvider != nullptr ? detailProvider() : nullptr;
|
||||
auto [trackName, eventName] = parseTrackName(entry.name);
|
||||
|
||||
if (performanceTracer.isTracing()) {
|
||||
std::optional<jsinspector_modern::DevToolsTrackEntryPayload>
|
||||
trackMetadata;
|
||||
|
||||
if (trackName.has_value()) {
|
||||
trackMetadata = {.track = trackName.value()};
|
||||
}
|
||||
performanceTracer.reportMeasure(
|
||||
eventName, entry.startTime, entry.duration, trackMetadata);
|
||||
}
|
||||
|
||||
if (ReactPerfettoLogger::isTracing()) {
|
||||
ReactPerfettoLogger::measure(
|
||||
entry.name,
|
||||
eventName,
|
||||
entry.startTime,
|
||||
entry.startTime + entry.duration,
|
||||
detail != nullptr ? getTrackFromDetail(detail) : std::nullopt,
|
||||
detail != nullptr ? getTrackGroupFromDetail(detail) : std::nullopt);
|
||||
}
|
||||
|
||||
if (performanceTracer.isTracing()) {
|
||||
performanceTracer.reportMeasure(
|
||||
entry.name, entry.startTime, entry.duration, std::move(detail));
|
||||
trackName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+11
-17
@@ -11,7 +11,7 @@
|
||||
#include "PerformanceEntryKeyedBuffer.h"
|
||||
#include "PerformanceObserverRegistry.h"
|
||||
|
||||
#include <folly/dynamic.h>
|
||||
#include <jsinspector-modern/tracing/CdpTracing.h>
|
||||
#include <react/timing/primitives.h>
|
||||
|
||||
#include <memory>
|
||||
@@ -86,18 +86,16 @@ class PerformanceEntryReporter {
|
||||
std::optional<HighResTimeStamp> getMarkTime(
|
||||
const std::string& markName) const;
|
||||
|
||||
using UserTimingDetailProvider = std::function<folly::dynamic()>;
|
||||
PerformanceMark reportMark(
|
||||
const std::string& name,
|
||||
const std::optional<HighResTimeStamp>& startTime = std::nullopt);
|
||||
|
||||
void reportMark(
|
||||
PerformanceMeasure reportMeasure(
|
||||
const std::string& name,
|
||||
HighResTimeStamp startTime,
|
||||
UserTimingDetailProvider&& detailProvider = nullptr);
|
||||
|
||||
void reportMeasure(
|
||||
const std::string& name,
|
||||
HighResTimeStamp startTime,
|
||||
HighResDuration duration,
|
||||
UserTimingDetailProvider&& detailProvider = nullptr);
|
||||
HighResTimeStamp endTime,
|
||||
const std::optional<jsinspector_modern::DevToolsTrackEntryPayload>&
|
||||
trackMetadata = std::nullopt);
|
||||
|
||||
void reportEvent(
|
||||
std::string name,
|
||||
@@ -109,7 +107,7 @@ class PerformanceEntryReporter {
|
||||
|
||||
void reportLongTask(HighResTimeStamp startTime, HighResDuration duration);
|
||||
|
||||
void reportResourceTiming(
|
||||
PerformanceResourceTiming reportResourceTiming(
|
||||
const std::string& url,
|
||||
HighResTimeStamp fetchStart,
|
||||
HighResTimeStamp requestStart,
|
||||
@@ -171,12 +169,8 @@ class PerformanceEntryReporter {
|
||||
throw std::logic_error("Unhandled PerformanceEntryType");
|
||||
}
|
||||
|
||||
void traceMark(
|
||||
const PerformanceMark& entry,
|
||||
UserTimingDetailProvider&& detailProvider) const;
|
||||
void traceMeasure(
|
||||
const PerformanceMeasure& entry,
|
||||
UserTimingDetailProvider&& detailProvider) const;
|
||||
void traceMark(const PerformanceMark& entry) const;
|
||||
void traceMeasure(const PerformanceMeasure& entry) const;
|
||||
};
|
||||
|
||||
} // namespace facebook::react
|
||||
|
||||
+28
-16
@@ -129,16 +129,20 @@ TEST(PerformanceEntryReporter, PerformanceEntryReporterTestReportMeasures) {
|
||||
"mark2", timeOrigin + HighResDuration::fromMilliseconds(2));
|
||||
|
||||
reporter->reportMeasure(
|
||||
"measure0", timeOrigin, HighResDuration::fromMilliseconds(2));
|
||||
"measure0",
|
||||
timeOrigin,
|
||||
timeOrigin + HighResDuration::fromMilliseconds(2));
|
||||
reporter->reportMeasure(
|
||||
"measure1", timeOrigin, HighResDuration::fromMilliseconds(3));
|
||||
"measure1",
|
||||
timeOrigin,
|
||||
timeOrigin + HighResDuration::fromMilliseconds(3));
|
||||
|
||||
reporter->reportMark(
|
||||
"mark3", timeOrigin + HighResDuration::fromNanoseconds(2.5 * 1e6));
|
||||
reporter->reportMeasure(
|
||||
"measure2",
|
||||
timeOrigin + HighResDuration::fromMilliseconds(2),
|
||||
HighResDuration::fromMilliseconds(2));
|
||||
timeOrigin + HighResDuration::fromMilliseconds(2));
|
||||
reporter->reportMark(
|
||||
"mark4", timeOrigin + HighResDuration::fromMilliseconds(3));
|
||||
|
||||
@@ -168,7 +172,7 @@ TEST(PerformanceEntryReporter, PerformanceEntryReporterTestReportMeasures) {
|
||||
PerformanceMeasure{
|
||||
{.name = "measure2",
|
||||
.startTime = timeOrigin + HighResDuration::fromMilliseconds(2),
|
||||
.duration = HighResDuration::fromMilliseconds(2)}},
|
||||
.duration = HighResDuration::zero()}},
|
||||
PerformanceMark{
|
||||
{.name = "mark3",
|
||||
.startTime =
|
||||
@@ -199,17 +203,21 @@ TEST(PerformanceEntryReporter, PerformanceEntryReporterTestGetEntries) {
|
||||
"mark2", timeOrigin + HighResDuration::fromMilliseconds(2));
|
||||
|
||||
reporter->reportMeasure(
|
||||
"common_name", timeOrigin, HighResDuration::fromMilliseconds(2));
|
||||
"common_name",
|
||||
timeOrigin,
|
||||
timeOrigin + HighResDuration::fromMilliseconds(2));
|
||||
reporter->reportMeasure(
|
||||
"measure1", timeOrigin, HighResDuration::fromMilliseconds(3));
|
||||
"measure1",
|
||||
timeOrigin,
|
||||
timeOrigin + HighResDuration::fromMilliseconds(3));
|
||||
reporter->reportMeasure(
|
||||
"measure2",
|
||||
timeOrigin + HighResDuration::fromMilliseconds(1),
|
||||
HighResDuration::fromMilliseconds(6));
|
||||
timeOrigin + HighResDuration::fromMilliseconds(6));
|
||||
reporter->reportMeasure(
|
||||
"measure3",
|
||||
timeOrigin + HighResDuration::fromNanoseconds(1.5 * 1e6),
|
||||
HighResDuration::fromMilliseconds(2));
|
||||
timeOrigin + HighResDuration::fromMilliseconds(2));
|
||||
|
||||
{
|
||||
const auto allEntries = toSorted(reporter->getEntries());
|
||||
@@ -233,12 +241,12 @@ TEST(PerformanceEntryReporter, PerformanceEntryReporterTestGetEntries) {
|
||||
PerformanceMeasure{
|
||||
{.name = "measure2",
|
||||
.startTime = timeOrigin + HighResDuration::fromMilliseconds(1),
|
||||
.duration = HighResDuration::fromMilliseconds(6)}},
|
||||
.duration = HighResDuration::fromMilliseconds(5)}},
|
||||
PerformanceMeasure{
|
||||
{.name = "measure3",
|
||||
.startTime =
|
||||
timeOrigin + HighResDuration::fromNanoseconds(1.5 * 1e6),
|
||||
.duration = HighResDuration::fromMilliseconds(2)}},
|
||||
.duration = HighResDuration::fromNanoseconds(0.5 * 1e6)}},
|
||||
PerformanceMark{
|
||||
{.name = "mark2",
|
||||
.startTime = timeOrigin + HighResDuration::fromMilliseconds(2),
|
||||
@@ -280,12 +288,12 @@ TEST(PerformanceEntryReporter, PerformanceEntryReporterTestGetEntries) {
|
||||
PerformanceMeasure{
|
||||
{.name = "measure2",
|
||||
.startTime = timeOrigin + HighResDuration::fromMilliseconds(1),
|
||||
.duration = HighResDuration::fromMilliseconds(6)}},
|
||||
.duration = HighResDuration::fromMilliseconds(5)}},
|
||||
PerformanceMeasure{
|
||||
{.name = "measure3",
|
||||
.startTime =
|
||||
timeOrigin + HighResDuration::fromNanoseconds(1.5 * 1e6),
|
||||
.duration = HighResDuration::fromMilliseconds(2)}}};
|
||||
.duration = HighResDuration::fromNanoseconds(0.5 * 1e6)}}};
|
||||
ASSERT_EQ(expected, measures);
|
||||
}
|
||||
|
||||
@@ -322,17 +330,21 @@ TEST(PerformanceEntryReporter, PerformanceEntryReporterTestClearMarks) {
|
||||
"mark2", timeOrigin + HighResDuration::fromMilliseconds(2));
|
||||
|
||||
reporter->reportMeasure(
|
||||
"common_name", timeOrigin, HighResDuration::fromMilliseconds(2));
|
||||
"common_name",
|
||||
timeOrigin,
|
||||
timeOrigin + HighResDuration::fromMilliseconds(2));
|
||||
reporter->reportMeasure(
|
||||
"measure1", timeOrigin, HighResDuration::fromMilliseconds(3));
|
||||
"measure1",
|
||||
timeOrigin,
|
||||
timeOrigin + HighResDuration::fromMilliseconds(3));
|
||||
reporter->reportMeasure(
|
||||
"measure2",
|
||||
timeOrigin + HighResDuration::fromMilliseconds(1),
|
||||
HighResDuration::fromMilliseconds(6));
|
||||
timeOrigin + HighResDuration::fromMilliseconds(6));
|
||||
reporter->reportMeasure(
|
||||
"measure3",
|
||||
timeOrigin + HighResDuration::fromNanoseconds(1.5 * 1e6),
|
||||
HighResDuration::fromMilliseconds(2));
|
||||
timeOrigin + HighResDuration::fromMilliseconds(2));
|
||||
|
||||
reporter->clearEntries(PerformanceEntryType::MARK, "common_name");
|
||||
|
||||
|
||||
+4
-2
@@ -190,7 +190,7 @@ TEST(PerformanceObserver, PerformanceObserverTestObserveTakeRecords) {
|
||||
reporter->reportMeasure(
|
||||
"off",
|
||||
timeOrigin + HighResDuration::fromMilliseconds(10),
|
||||
HighResDuration::fromMilliseconds(20));
|
||||
timeOrigin + HighResDuration::fromMilliseconds(20));
|
||||
reporter->reportMark(
|
||||
"test2", timeOrigin + HighResDuration::fromMilliseconds(20));
|
||||
reporter->reportMark(
|
||||
@@ -371,7 +371,9 @@ TEST(PerformanceObserver, PerformanceObserverTestMultiple) {
|
||||
{.durationThreshold = HighResDuration::fromMilliseconds(80)});
|
||||
|
||||
reporter->reportMeasure(
|
||||
"measure", timeOrigin, HighResDuration::fromMilliseconds(50));
|
||||
"measure",
|
||||
timeOrigin,
|
||||
timeOrigin + HighResDuration::fromMilliseconds(50));
|
||||
reporter->reportEvent(
|
||||
"event1",
|
||||
timeOrigin,
|
||||
|
||||
-8
@@ -33,14 +33,6 @@ class ScrollViewState final {
|
||||
Rect contentBoundingRect;
|
||||
int scrollAwayPaddingTop;
|
||||
|
||||
/*
|
||||
* View Culling has to be disabled when accessibility features are used.
|
||||
* View Culling removes views from view hierarchy and for example VoiceOver
|
||||
* wouldn't recognise there is a view outside of the viewport that it can
|
||||
* scroll to.
|
||||
*/
|
||||
bool disableViewCulling{false};
|
||||
|
||||
/*
|
||||
* Returns size of scrollable area.
|
||||
*/
|
||||
|
||||
@@ -550,13 +550,6 @@ BorderMetrics BaseViewProps::resolveBorderMetrics(
|
||||
Transform BaseViewProps::resolveTransform(
|
||||
const LayoutMetrics& layoutMetrics) const {
|
||||
const auto& frameSize = layoutMetrics.frame.size;
|
||||
return resolveTransform(frameSize, transform, transformOrigin);
|
||||
}
|
||||
|
||||
Transform BaseViewProps::resolveTransform(
|
||||
const Size& frameSize,
|
||||
const Transform& transform,
|
||||
const TransformOrigin& transformOrigin) {
|
||||
auto transformMatrix = Transform{};
|
||||
if (frameSize.width == 0 && frameSize.height == 0) {
|
||||
return transformMatrix;
|
||||
@@ -569,7 +562,8 @@ Transform BaseViewProps::resolveTransform(
|
||||
} else {
|
||||
for (const auto& operation : transform.operations) {
|
||||
transformMatrix = transformMatrix *
|
||||
Transform::FromTransformOperation(operation, frameSize, transform);
|
||||
Transform::FromTransformOperation(
|
||||
operation, layoutMetrics.frame.size, transform);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -108,11 +108,6 @@ class BaseViewProps : public YogaStylableProps, public AccessibilityProps {
|
||||
Transform resolveTransform(const LayoutMetrics& layoutMetrics) const;
|
||||
bool getClipsContentToBounds() const;
|
||||
|
||||
static Transform resolveTransform(
|
||||
const Size& frameSize,
|
||||
const Transform& transform,
|
||||
const TransformOrigin& transformOrigin);
|
||||
|
||||
#if RN_DEBUG_STRING_CONVERTIBLE
|
||||
SharedDebugStringConvertibleList getDebugProps() const override;
|
||||
#endif
|
||||
|
||||
@@ -74,15 +74,10 @@ class ConcreteState : public State {
|
||||
* function for cases where a new value of data does not depend on an old
|
||||
* value.
|
||||
*/
|
||||
void updateState(
|
||||
Data&& newData,
|
||||
EventQueue::UpdateMode updateMode =
|
||||
EventQueue::UpdateMode::Asynchronous) const {
|
||||
updateState(
|
||||
[data{std::move(newData)}](const Data& /*oldData*/) -> SharedData {
|
||||
return std::make_shared<const Data>(data);
|
||||
},
|
||||
updateMode);
|
||||
void updateState(Data&& newData) const {
|
||||
updateState([data{std::move(newData)}](const Data& oldData) -> SharedData {
|
||||
return std::make_shared<const Data>(data);
|
||||
});
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -94,9 +89,7 @@ class ConcreteState : public State {
|
||||
* return `nullptr`.
|
||||
*/
|
||||
void updateState(
|
||||
std::function<StateData::Shared(const Data& oldData)> callback,
|
||||
EventQueue::UpdateMode updateMode =
|
||||
EventQueue::UpdateMode::Asynchronous) const {
|
||||
std::function<StateData::Shared(const Data& oldData)> callback) const {
|
||||
auto family = family_.lock();
|
||||
|
||||
if (!family) {
|
||||
@@ -111,7 +104,7 @@ class ConcreteState : public State {
|
||||
return callback(*static_cast<const Data*>(oldData.get()));
|
||||
}};
|
||||
|
||||
family->dispatchRawState(std::move(stateUpdate), updateMode);
|
||||
family->dispatchRawState(std::move(stateUpdate));
|
||||
}
|
||||
|
||||
#if defined(RN_SERIALIZABLE_STATE)
|
||||
|
||||
@@ -41,10 +41,8 @@ void EventDispatcher::experimental_flushSync() const {
|
||||
eventQueue_.experimental_flushSync();
|
||||
}
|
||||
|
||||
void EventDispatcher::dispatchStateUpdate(
|
||||
StateUpdate&& stateUpdate,
|
||||
EventQueue::UpdateMode updateMode) const {
|
||||
eventQueue_.enqueueStateUpdate(std::move(stateUpdate), updateMode);
|
||||
void EventDispatcher::dispatchStateUpdate(StateUpdate&& stateUpdate) const {
|
||||
eventQueue_.enqueueStateUpdate(std::move(stateUpdate));
|
||||
}
|
||||
|
||||
void EventDispatcher::dispatchUniqueEvent(RawEvent&& rawEvent) const {
|
||||
|
||||
@@ -56,9 +56,7 @@ class EventDispatcher {
|
||||
/*
|
||||
* Dispatches a state update with given priority.
|
||||
*/
|
||||
void dispatchStateUpdate(
|
||||
StateUpdate&& stateUpdate,
|
||||
EventQueue::UpdateMode updateMode) const;
|
||||
void dispatchStateUpdate(StateUpdate&& stateUpdate) const;
|
||||
|
||||
#pragma mark - Event listeners
|
||||
/*
|
||||
|
||||
@@ -61,9 +61,7 @@ void EventQueue::enqueueUniqueEvent(RawEvent&& rawEvent) const {
|
||||
enqueueEvent(std::move(rawEvent));
|
||||
}
|
||||
|
||||
void EventQueue::enqueueStateUpdate(
|
||||
StateUpdate&& stateUpdate,
|
||||
UpdateMode updateMode) const {
|
||||
void EventQueue::enqueueStateUpdate(StateUpdate&& stateUpdate) const {
|
||||
{
|
||||
std::scoped_lock lock(queueMutex_);
|
||||
if (!stateUpdateQueue_.empty()) {
|
||||
@@ -75,11 +73,7 @@ void EventQueue::enqueueStateUpdate(
|
||||
stateUpdateQueue_.push_back(std::move(stateUpdate));
|
||||
}
|
||||
|
||||
if (updateMode == UpdateMode::unstable_Immediate) {
|
||||
flushStateUpdates();
|
||||
} else {
|
||||
onEnqueue();
|
||||
}
|
||||
onEnqueue();
|
||||
}
|
||||
|
||||
void EventQueue::onEnqueue() const {
|
||||
|
||||
@@ -25,18 +25,6 @@ namespace facebook::react {
|
||||
*/
|
||||
class EventQueue {
|
||||
public:
|
||||
/* The update mode is used to inform how to apply changes. */
|
||||
enum class UpdateMode {
|
||||
/** Apply the update off the main thread. */
|
||||
Asynchronous,
|
||||
/**
|
||||
* Apply the update on the main thread.
|
||||
* The immediate update mode will **immediately** block the executing thread
|
||||
* applying updates.
|
||||
*/
|
||||
unstable_Immediate,
|
||||
};
|
||||
|
||||
EventQueue(
|
||||
EventQueueProcessor eventProcessor,
|
||||
std::unique_ptr<EventBeat> eventBeat);
|
||||
@@ -58,9 +46,7 @@ class EventQueue {
|
||||
* Enqueues and (probably later) dispatch a given state update.
|
||||
* Can be called on any thread.
|
||||
*/
|
||||
void enqueueStateUpdate(
|
||||
StateUpdate&& stateUpdate,
|
||||
UpdateMode updateMode = UpdateMode::Asynchronous) const;
|
||||
void enqueueStateUpdate(StateUpdate&& stateUpdate) const;
|
||||
|
||||
/*
|
||||
* Experimental API exposed to support EventEmitter::experimental_flushSync.
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user