mirror of
https://github.com/facebook/react-native.git
synced 2025-11-01 09:14:26 +00:00
Compare commits
41
Commits
export-D85546696
...
main
@@ -121,7 +121,7 @@ describe('Create Draft Release', () => {
|
||||
});
|
||||
|
||||
describe('#_computeBody', () => {
|
||||
it('computes body for release', async () => {
|
||||
it('computes body for release when no hermes versions are passed', async () => {
|
||||
const version = '0.77.1';
|
||||
const changelog = `## v${version}
|
||||
### Breaking Changes
|
||||
@@ -134,20 +134,83 @@ describe('Create Draft Release', () => {
|
||||
#### iOS
|
||||
- [PR #3436](https://github.com/facebook/react-native/pull/3436) - Some other change
|
||||
- [PR #3437](https://github.com/facebook/react-native/pull/3437) - Some other change`;
|
||||
const body = _computeBody(version, changelog);
|
||||
const body = _computeBody(changelog, version);
|
||||
|
||||
expect(body).toEqual(`${changelog}
|
||||
|
||||
---
|
||||
|
||||
Hermes dSYMS:
|
||||
- [Debug](https://repo1.maven.org/maven2/com/facebook/react/react-native-artifacts/${version}/react-native-artifacts-${version}-hermes-framework-dSYM-debug.tar.gz)
|
||||
- [Release](https://repo1.maven.org/maven2/com/facebook/react/react-native-artifacts/${version}/react-native-artifacts-${version}-hermes-framework-dSYM-release.tar.gz)
|
||||
- [Debug](https://repo1.maven.org/maven2/com/facebook/hermes/hermes-ios/${version}/hermes-ios-${version}-hermes-framework-dSYM-debug.tar.gz)
|
||||
- [Release](https://repo1.maven.org/maven2/com/facebook/hermes/hermes-ios/${version}/hermes-ios-${version}-hermes-framework-dSYM-release.tar.gz)
|
||||
|
||||
Hermes V1 dSYMS:
|
||||
- [Debug](https://repo1.maven.org/maven2/com/facebook/hermes/hermes-ios/${version}/hermes-ios-${version}-hermes-framework-dSYM-debug.tar.gz)
|
||||
- [Release](https://repo1.maven.org/maven2/com/facebook/hermes/hermes-ios/${version}/hermes-ios-${version}-hermes-framework-dSYM-release.tar.gz)
|
||||
|
||||
ReactNativeDependencies dSYMs:
|
||||
- [Debug](https://repo1.maven.org/maven2/com/facebook/react/react-native-artifacts/${version}/react-native-artifacts-${version}-reactnative-dependencies-dSYM-debug.tar.gz)
|
||||
- [Release](https://repo1.maven.org/maven2/com/facebook/react/react-native-artifacts/${version}/react-native-artifacts-${version}-reactnative-dependencies-dSYM-release.tar.gz)
|
||||
|
||||
ReactNative Core dSYMs:
|
||||
- [Debug](https://repo1.maven.org/maven2/com/facebook/react/react-native-artifacts/${version}/react-native-artifacts-${version}-reactnative-core-debug.tar.gz)
|
||||
- [Release](https://repo1.maven.org/maven2/com/facebook/react/react-native-artifacts/${version}/react-native-artifacts-${version}-reactnative-core-release.tar.gz)
|
||||
|
||||
---
|
||||
|
||||
You can file issues or pick requests against this release [here](https://github.com/reactwg/react-native-releases/issues/new/choose).
|
||||
|
||||
---
|
||||
|
||||
To help you upgrade to this version, you can use the [Upgrade Helper](https://react-native-community.github.io/upgrade-helper/) ⚛️.
|
||||
|
||||
---
|
||||
|
||||
View the whole changelog in the [CHANGELOG.md file](https://github.com/facebook/react-native/blob/main/CHANGELOG.md).`);
|
||||
});
|
||||
|
||||
it('computes body for release when hermes versions are passed', async () => {
|
||||
const version = '0.77.1';
|
||||
const hermesVersion = '0.15.0';
|
||||
const hermesV1Version = '250829098.0.2';
|
||||
const changelog = `## v${version}
|
||||
### Breaking Changes
|
||||
- [PR #9012](https://github.com/facebook/react-native/pull/9012) - Some other change
|
||||
|
||||
#### Android
|
||||
- [PR #3456](https://github.com/facebook/react-native/pull/3456) - Some other change
|
||||
- [PR #3457](https://github.com/facebook/react-native/pull/3457) - Some other change
|
||||
|
||||
#### iOS
|
||||
- [PR #3436](https://github.com/facebook/react-native/pull/3436) - Some other change
|
||||
- [PR #3437](https://github.com/facebook/react-native/pull/3437) - Some other change`;
|
||||
const body = _computeBody(
|
||||
changelog,
|
||||
version,
|
||||
hermesVersion,
|
||||
hermesV1Version,
|
||||
);
|
||||
|
||||
expect(body).toEqual(`${changelog}
|
||||
|
||||
---
|
||||
|
||||
Hermes dSYMS:
|
||||
- [Debug](https://repo1.maven.org/maven2/com/facebook/hermes/hermes-ios/${hermesVersion}/hermes-ios-${hermesVersion}-hermes-framework-dSYM-debug.tar.gz)
|
||||
- [Release](https://repo1.maven.org/maven2/com/facebook/hermes/hermes-ios/${hermesVersion}/hermes-ios-${hermesVersion}-hermes-framework-dSYM-release.tar.gz)
|
||||
|
||||
Hermes V1 dSYMS:
|
||||
- [Debug](https://repo1.maven.org/maven2/com/facebook/hermes/hermes-ios/${hermesV1Version}/hermes-ios-${hermesV1Version}-hermes-framework-dSYM-debug.tar.gz)
|
||||
- [Release](https://repo1.maven.org/maven2/com/facebook/hermes/hermes-ios/${hermesV1Version}/hermes-ios-${hermesV1Version}-hermes-framework-dSYM-release.tar.gz)
|
||||
|
||||
ReactNativeDependencies dSYMs:
|
||||
- [Debug](https://repo1.maven.org/maven2/com/facebook/react/react-native-artifacts/${version}/react-native-artifacts-${version}-reactnative-dependencies-dSYM-debug.tar.gz)
|
||||
- [Release](https://repo1.maven.org/maven2/com/facebook/react/react-native-artifacts/${version}/react-native-artifacts-${version}-reactnative-dependencies-dSYM-release.tar.gz)
|
||||
|
||||
ReactNative Core dSYMs:
|
||||
- [Debug](https://repo1.maven.org/maven2/com/facebook/react/react-native-artifacts/${version}/react-native-artifacts-${version}-reactnative-core-debug.tar.gz)
|
||||
- [Release](https://repo1.maven.org/maven2/com/facebook/react/react-native-artifacts/${version}/react-native-artifacts-${version}-reactnative-core-release.tar.gz)
|
||||
|
||||
---
|
||||
|
||||
You can file issues or pick requests against this release [here](https://github.com/reactwg/react-native-releases/issues/new/choose).
|
||||
|
||||
@@ -40,19 +40,29 @@ function _extractChangelog(version) {
|
||||
return changelog.slice(changelogStarts, changelogEnds).join('\n').trim();
|
||||
}
|
||||
|
||||
function _computeBody(version, changelog) {
|
||||
function _computeBody(changelog, version, hermesVersion, hermesV1Version) {
|
||||
hermesVersion = hermesVersion ?? version;
|
||||
hermesV1Version = hermesV1Version ?? version;
|
||||
return `${changelog}
|
||||
|
||||
---
|
||||
|
||||
Hermes dSYMS:
|
||||
- [Debug](https://repo1.maven.org/maven2/com/facebook/react/react-native-artifacts/${version}/react-native-artifacts-${version}-hermes-framework-dSYM-debug.tar.gz)
|
||||
- [Release](https://repo1.maven.org/maven2/com/facebook/react/react-native-artifacts/${version}/react-native-artifacts-${version}-hermes-framework-dSYM-release.tar.gz)
|
||||
- [Debug](https://repo1.maven.org/maven2/com/facebook/hermes/hermes-ios/${hermesVersion}/hermes-ios-${hermesVersion}-hermes-framework-dSYM-debug.tar.gz)
|
||||
- [Release](https://repo1.maven.org/maven2/com/facebook/hermes/hermes-ios/${hermesVersion}/hermes-ios-${hermesVersion}-hermes-framework-dSYM-release.tar.gz)
|
||||
|
||||
Hermes V1 dSYMS:
|
||||
- [Debug](https://repo1.maven.org/maven2/com/facebook/hermes/hermes-ios/${hermesV1Version}/hermes-ios-${hermesV1Version}-hermes-framework-dSYM-debug.tar.gz)
|
||||
- [Release](https://repo1.maven.org/maven2/com/facebook/hermes/hermes-ios/${hermesV1Version}/hermes-ios-${hermesV1Version}-hermes-framework-dSYM-release.tar.gz)
|
||||
|
||||
ReactNativeDependencies dSYMs:
|
||||
- [Debug](https://repo1.maven.org/maven2/com/facebook/react/react-native-artifacts/${version}/react-native-artifacts-${version}-reactnative-dependencies-dSYM-debug.tar.gz)
|
||||
- [Release](https://repo1.maven.org/maven2/com/facebook/react/react-native-artifacts/${version}/react-native-artifacts-${version}-reactnative-dependencies-dSYM-release.tar.gz)
|
||||
|
||||
ReactNative Core dSYMs:
|
||||
- [Debug](https://repo1.maven.org/maven2/com/facebook/react/react-native-artifacts/${version}/react-native-artifacts-${version}-reactnative-core-debug.tar.gz)
|
||||
- [Release](https://repo1.maven.org/maven2/com/facebook/react/react-native-artifacts/${version}/react-native-artifacts-${version}-reactnative-core-release.tar.gz)
|
||||
|
||||
---
|
||||
|
||||
You can file issues or pick requests against this release [here](https://github.com/reactwg/react-native-releases/issues/new/choose).
|
||||
@@ -113,7 +123,13 @@ function moveToChangelogBranch(version) {
|
||||
run(`git checkout -b changelog/v${version}`);
|
||||
}
|
||||
|
||||
async function createDraftRelease(version, latest, token) {
|
||||
async function createDraftRelease(
|
||||
version,
|
||||
latest,
|
||||
token,
|
||||
hermesVersion,
|
||||
hermesV1Version,
|
||||
) {
|
||||
if (version.startsWith('v')) {
|
||||
version = version.substring(1);
|
||||
}
|
||||
@@ -121,7 +137,7 @@ async function createDraftRelease(version, latest, token) {
|
||||
_verifyTagExists(version);
|
||||
moveToChangelogBranch(version);
|
||||
const changelog = _extractChangelog(version);
|
||||
const body = _computeBody(version, changelog);
|
||||
const body = _computeBody(changelog, version, hermesVersion, hermesV1Version);
|
||||
const release = await _createDraftReleaseOnGitHub(
|
||||
version,
|
||||
body,
|
||||
|
||||
@@ -2,6 +2,15 @@ name: Create Draft Release
|
||||
|
||||
on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
hermesVersion:
|
||||
required: false
|
||||
type: string
|
||||
description: The version of Hermes to use for this release (eg. 0.15.0). If not specified, it will use React Native Version
|
||||
hermesV1Version:
|
||||
required: false
|
||||
type: string
|
||||
description: The version of Hermes V1 to use for this release (eg. 250829098.0.2). If not specified, it will use React Native Version
|
||||
|
||||
jobs:
|
||||
create-draft-release:
|
||||
@@ -27,7 +36,7 @@ jobs:
|
||||
const {createDraftRelease} = require('./.github/workflow-scripts/createDraftRelease.js');
|
||||
const version = '${{ github.ref_name }}';
|
||||
const {isLatest} = require('./.github/workflow-scripts/publishTemplate.js');
|
||||
return (await createDraftRelease(version, isLatest(), '${{secrets.REACT_NATIVE_BOT_GITHUB_TOKEN}}')).id;
|
||||
return (await createDraftRelease(version, isLatest(), '${{secrets.REACT_NATIVE_BOT_GITHUB_TOKEN}}', ${{ inputs.hermesVersion }}, ${{ inputs.hermesV1Version }})).id;
|
||||
result-encoding: string
|
||||
- name: Upload release assets for DotSlash
|
||||
uses: actions/github-script@v6
|
||||
|
||||
@@ -19,6 +19,28 @@ jobs:
|
||||
echo "Setting release type to release"
|
||||
echo "RELEASE_TYPE=release" >> $GITHUB_OUTPUT
|
||||
|
||||
set_hermes_versions:
|
||||
runs-on: ubuntu-latest
|
||||
if: github.repository == 'facebook/react-native'
|
||||
outputs:
|
||||
HERMES_VERSION: ${{ steps.set_hermes_versions.outputs.HERMES_VERSION }}
|
||||
HERMES_V1_VERSION: ${{ steps.set_hermes_versions.outputs.HERMES_V1_VERSION }}
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
- id: set_hermes_versions
|
||||
run: |
|
||||
echo "Setting hermes versions to latest"
|
||||
hermes_version=$(grep -oE 'HERMES_VERSION_NAME=([0-9]+\.[0-9]+\.[0-9]+)' packages/react-native/sdks/hermes-engine/version.properties | cut -d'=' -f2)
|
||||
hermes_v1_version=$(grep -oE 'HERMES_V1_VERSION_NAME=([0-9]+\.[0-9]+\.[0-9]+)' packages/react-native/sdks/hermes-engine/version.properties | cut -d'=' -f2)
|
||||
|
||||
echo "HERMES_VERSION=$hermes_version" >> $GITHUB_OUTPUT
|
||||
echo "HERMES_V1_VERSION=$hermes_v1_version" >> $GITHUB_OUTPUT
|
||||
- name: Print hermes versions
|
||||
run: |
|
||||
echo "HERMES_VERSION=${{ steps.set_hermes_versions.outputs.HERMES_VERSION }}"
|
||||
echo "HERMES_V1_VERSION=${{ steps.set_hermes_versions.outputs.HERMES_V1_VERSION }}"
|
||||
|
||||
prebuild_apple_dependencies:
|
||||
if: github.repository == 'facebook/react-native'
|
||||
uses: ./.github/workflows/prebuild-ios-dependencies.yml
|
||||
@@ -117,6 +139,9 @@ jobs:
|
||||
secrets: inherit
|
||||
|
||||
create_draft_release:
|
||||
needs: generate_changelog
|
||||
needs: [generate_changelog, set_hermes_versions]
|
||||
uses: ./.github/workflows/create-draft-release.yml
|
||||
secrets: inherit
|
||||
with:
|
||||
hermesVersion: ${{ needs.set_hermes_versions.outputs.HERMES_VERSION }}
|
||||
hermesV1Version: ${{ needs.set_hermes_versions.outputs.HERMES_V1_VERSION }}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
@generated SignedSource<<dc58cf17e902cabe1ef88730ce9e056e>>
|
||||
Git revision: 96e6bb8ecdff166816e2a469b7594f1276bda8c1
|
||||
@generated SignedSource<<4bb67766e15e25a481c4c38873260a7a>>
|
||||
Git revision: 7aa57d13e50ce9d74a91c9315c9b0ded00fbc19f
|
||||
Built with --nohooks: false
|
||||
Is local checkout: false
|
||||
Remote URL: https://github.com/facebook/react-native-devtools-frontend
|
||||
|
||||
+1
-1
File diff suppressed because one or more lines are too long
Vendored
+1
-1
@@ -1 +1 @@
|
||||
import*as e from"../root/root.js";const t=e.Runtime.RNExperimentName,n={didInitializeExperiments:!1,isReactNativeEntryPoint:!1};class i{name;title;unstable;docLink;feedbackLink;enabledByDefault;constructor(e){this.name=e.name,this.title=e.title,this.unstable=e.unstable,this.docLink=e.docLink,this.feedbackLink=e.feedbackLink,this.enabledByDefault=function(e,t){if(null==e)return()=>t;if("boolean"==typeof e)return()=>e;return e}(e.enabledByDefault,!1)}}const r=new class{#e=new Map;#t=new Set;register(e){if(n.didInitializeExperiments)throw new Error("Experiments must be registered before constructing MainImpl");const{name:t}=e;if(this.#e.has(t))throw new Error(`React Native Experiment ${t} is already registered`);this.#e.set(t,new i(e))}enableExperimentsByDefault(e){if(n.didInitializeExperiments)throw new Error("Experiments must be configured before constructing MainImpl");for(const n of e)if(Object.prototype.hasOwnProperty.call(t,n)){const e=this.#e.get(n);if(!e)throw new Error(`React Native Experiment ${n} is not registered`);e.enabledByDefault=()=>!0}else this.#t.add(n)}copyInto(e,t=""){for(const[i,r]of this.#e)e.register(i,t+r.title,r.unstable,r.docLink,r.feedbackLink),r.enabledByDefault({isReactNativeEntryPoint:n.isReactNativeEntryPoint})&&e.enableExperimentsByDefault([i]);for(const t of this.#t)e.enableExperimentsByDefault([t]);n.didInitializeExperiments=!0}};r.register({name:t.JS_HEAP_PROFILER_ENABLE,title:"Enable Heap Profiler (Memory Panel)",unstable:!1,enabledByDefault:({isReactNativeEntryPoint:e})=>!e}),r.register({name:t.REACT_NATIVE_SPECIFIC_UI,title:"Show React Native-specific UI",unstable:!1,enabledByDefault:({isReactNativeEntryPoint:e})=>e}),r.register({name:t.ENABLE_PERFORMANCE_PANEL,title:"Enable Performance panel",unstable:!0,enabledByDefault:({isReactNativeEntryPoint:e})=>!e}),r.register({name:t.ENABLE_NETWORK_PANEL,title:"Enable Network panel",unstable:!0,enabledByDefault:()=>!1});var a=Object.freeze({__proto__:null,Instance:r,RNExperimentName:t,setIsReactNativeEntryPoint:function(e){if(n.didInitializeExperiments)throw new Error("setIsReactNativeEntryPoint must be called before constructing MainImpl");n.isReactNativeEntryPoint=e}});export{a as RNExperimentsImpl};
|
||||
import*as e from"../root/root.js";const t=e.Runtime.RNExperimentName,i={didInitializeExperiments:!1,isReactNativeEntryPoint:!1};class n{name;title;unstable;docLink;feedbackLink;enabledByDefault;constructor(e){this.name=e.name,this.title=e.title,this.unstable=e.unstable,this.docLink=e.docLink,this.feedbackLink=e.feedbackLink,this.enabledByDefault=function(e,t){if(null==e)return()=>t;if("boolean"==typeof e)return()=>e;return e}(e.enabledByDefault,!1)}}const r=new class{#e=new Map;#t=new Set;register(e){if(i.didInitializeExperiments)throw new Error("Experiments must be registered before constructing MainImpl");const{name:t}=e;if(this.#e.has(t))throw new Error(`React Native Experiment ${t} is already registered`);this.#e.set(t,new n(e))}enableExperimentsByDefault(e){if(i.didInitializeExperiments)throw new Error("Experiments must be configured before constructing MainImpl");for(const i of e)if(Object.prototype.hasOwnProperty.call(t,i)){const e=this.#e.get(i);if(!e)throw new Error(`React Native Experiment ${i} is not registered`);e.enabledByDefault=()=>!0}else this.#t.add(i)}copyInto(e,t=""){for(const[n,r]of this.#e)e.register(n,t+r.title,r.unstable,r.docLink,r.feedbackLink),r.enabledByDefault({isReactNativeEntryPoint:i.isReactNativeEntryPoint})&&e.enableExperimentsByDefault([n]);for(const t of this.#t)e.enableExperimentsByDefault([t]);i.didInitializeExperiments=!0}};r.register({name:t.JS_HEAP_PROFILER_ENABLE,title:"Enable Heap Profiler (Memory Panel)",unstable:!1,enabledByDefault:({isReactNativeEntryPoint:e})=>!e}),r.register({name:t.REACT_NATIVE_SPECIFIC_UI,title:"Show React Native-specific UI",unstable:!1,enabledByDefault:({isReactNativeEntryPoint:e})=>e}),r.register({name:t.ENABLE_NETWORK_PANEL,title:"Enable Network panel",unstable:!0,enabledByDefault:()=>!1});var a=Object.freeze({__proto__:null,Instance:r,RNExperimentName:t,setIsReactNativeEntryPoint:function(e){if(i.didInitializeExperiments)throw new Error("setIsReactNativeEntryPoint must be called before constructing MainImpl");i.isReactNativeEntryPoint=e}});export{a as RNExperimentsImpl};
|
||||
|
||||
@@ -1 +1 @@
|
||||
import*as e from"../platform/platform.js";const t=new URLSearchParams(location.search);let n,r,s="";function a(){return window.location.pathname}function i(e){return["node_app","js_app"].some((t=>e.includes(t)))}class o{constructor(){}static instance(e={forceNew:null}){const{forceNew:t}=e;return n&&!t||(n=new o),n}static removeInstance(){n=void 0}static queryParam(e){return t.get(e)}static setQueryParamForTesting(e,n){t.set(e,n)}static isNode(){return void 0===r&&(r=i(a())),r}static setPlatform(e){s=e}static platform(){return s}static isDescriptorEnabled(e){const{experiment:t}=e;if("*"===t)return!0;if(t&&t.startsWith("!")&&h.isEnabled(t.substring(1)))return!1;if(t&&!t.startsWith("!")&&!h.isEnabled(t))return!1;const{condition:n}=e;return!n||n(_)}loadLegacyModule(e){console.log("Loading legacy module: "+e);return import(`../../${e}`).then((t=>(console.log("Loaded legacy module: "+e),t)))}}class l{#e=[];#t=new Set;#n=new Set;#r=new Set;#s=new Set;#a=new c;allConfigurableExperiments(){const e=[];for(const t of this.#e)this.#n.has(t.name)||e.push(t);return e}register(t,n,r,s,a){if(this.#t.has(t))throw new Error(`Duplicate registration of experiment '${t}'`);this.#t.add(t),this.#e.push(new m(this,t,n,Boolean(r),s??e.DevToolsPath.EmptyUrlString,a??e.DevToolsPath.EmptyUrlString))}isEnabled(e){return this.checkExperiment(e),!1!==this.#a.get(e)&&(!(!this.#n.has(e)&&!this.#r.has(e))||(!!this.#s.has(e)||Boolean(this.#a.get(e))))}setEnabled(e,t){this.checkExperiment(e),this.#a.set(e,t)}enableExperimentsTransiently(e){for(const t of e)this.checkExperiment(t),this.#n.add(t)}enableExperimentsByDefault(e){for(const t of e)this.checkExperiment(t),this.#r.add(t)}setServerEnabledExperiments(e){for(const t of e)this.checkExperiment(t),this.#s.add(t)}enableForTest(e){this.checkExperiment(e),this.#n.add(e)}disableForTest(e){this.checkExperiment(e),this.#n.delete(e)}clearForTest(){this.#e=[],this.#t.clear(),this.#n.clear(),this.#r.clear(),this.#s.clear()}cleanUpStaleExperiments(){this.#a.cleanUpStaleExperiments(this.#t)}checkExperiment(e){if(!this.#t.has(e))throw new Error(`Unknown experiment '${e}'`)}}class c{#e={};constructor(){try{const e=self.localStorage?.getItem("experiments");e&&(this.#e=JSON.parse(e))}catch{console.error("Failed to parse localStorage['experiments']")}}get(e){return this.#e[e]}set(e,t){this.#e[e]=t,this.#i()}cleanUpStaleExperiments(e){for(const[t]of Object.entries(this.#e))e.has(t)||delete this.#e[t];this.#i()}#i(){self.localStorage?.setItem("experiments",JSON.stringify(this.#e))}}class m{name;title;unstable;docLink;feedbackLink;#e;constructor(e,t,n,r,s,a){this.name=t,this.title=n,this.unstable=r,this.docLink=s,this.feedbackLink=a,this.#e=e}isEnabled(){return this.#e.isEnabled(this.name)}setEnabled(e){this.#e.setEnabled(this.name,e)}}const h=new l;var E,p,d,u;!function(e){e.REACT_NATIVE_SPECIFIC_UI="react-native-specific-ui",e.JS_HEAP_PROFILER_ENABLE="js-heap-profiler-enable",e.ENABLE_PERFORMANCE_PANEL="enable-performance-panel",e.ENABLE_NETWORK_PANEL="enable-network-panel"}(E||(E={})),function(e){e.NOT_SOURCES_HIDE_ADD_FOLDER="!sources.hide_add_folder",e.REACT_NATIVE_UNSTABLE_NETWORK_PANEL="unstable_enableNetworkPanel"}(p||(p={})),function(e){e[e.ALLOW=0]="ALLOW",e[e.ALLOW_WITHOUT_LOGGING=1]="ALLOW_WITHOUT_LOGGING",e[e.DISABLE=2]="DISABLE"}(d||(d={})),function(e){e.ALL_SCRIPTS="ALL_SCRIPTS",e.SIDE_EFFECT_FREE_SCRIPTS_ONLY="SIDE_EFFECT_FREE_SCRIPTS_ONLY",e.NO_SCRIPTS="NO_SCRIPTS"}(u||(u={}));const _=Object.create(null),f={canDock:()=>Boolean(o.queryParam("can_dock")),notSourcesHideAddFolder:()=>Boolean(o.queryParam(p.NOT_SOURCES_HIDE_ADD_FOLDER)),reactNativeUnstableNetworkPanel:()=>Boolean(o.queryParam(p.REACT_NATIVE_UNSTABLE_NETWORK_PANEL))||h.isEnabled("enable-network-panel")};var x=Object.freeze({__proto__:null,get ConditionName(){return p},Experiment:m,ExperimentsSupport:l,get GenAiEnterprisePolicyValue(){return d},get HostConfigFreestylerExecutionMode(){return u},get RNExperimentName(){return E},Runtime:o,conditions:f,experiments:h,getChromeVersion:()=>{const e=navigator.userAgent.match(/(?:^|\W)(?:Chrome|HeadlessChrome)\/(\S+)/);return e&&e.length>1?e[1]:""},getPathName:a,getRemoteBase:function(e=self.location.toString()){const t=new URL(e).searchParams.get("remoteBase");if(!t)return null;const n=/\/serve_file\/(@[0-9a-zA-Z]+)\/?$/.exec(t);return n?{base:`devtools://devtools/remote/serve_file/${n[1]}/`,version:n[1]}:null},hostConfig:_,isNodeEntry:i});export{x as Runtime};
|
||||
import*as e from"../platform/platform.js";const t=new URLSearchParams(location.search);let n,r,s="";function a(){return window.location.pathname}function i(e){return["node_app","js_app"].some((t=>e.includes(t)))}class o{constructor(){}static instance(e={forceNew:null}){const{forceNew:t}=e;return n&&!t||(n=new o),n}static removeInstance(){n=void 0}static queryParam(e){return t.get(e)}static setQueryParamForTesting(e,n){t.set(e,n)}static isNode(){return void 0===r&&(r=i(a())),r}static setPlatform(e){s=e}static platform(){return s}static isDescriptorEnabled(e){const{experiment:t}=e;if("*"===t)return!0;if(t&&t.startsWith("!")&&h.isEnabled(t.substring(1)))return!1;if(t&&!t.startsWith("!")&&!h.isEnabled(t))return!1;const{condition:n}=e;return!n||n(_)}loadLegacyModule(e){console.log("Loading legacy module: "+e);return import(`../../${e}`).then((t=>(console.log("Loaded legacy module: "+e),t)))}}class l{#e=[];#t=new Set;#n=new Set;#r=new Set;#s=new Set;#a=new c;allConfigurableExperiments(){const e=[];for(const t of this.#e)this.#n.has(t.name)||e.push(t);return e}register(t,n,r,s,a){if(this.#t.has(t))throw new Error(`Duplicate registration of experiment '${t}'`);this.#t.add(t),this.#e.push(new m(this,t,n,Boolean(r),s??e.DevToolsPath.EmptyUrlString,a??e.DevToolsPath.EmptyUrlString))}isEnabled(e){return this.checkExperiment(e),!1!==this.#a.get(e)&&(!(!this.#n.has(e)&&!this.#r.has(e))||(!!this.#s.has(e)||Boolean(this.#a.get(e))))}setEnabled(e,t){this.checkExperiment(e),this.#a.set(e,t)}enableExperimentsTransiently(e){for(const t of e)this.checkExperiment(t),this.#n.add(t)}enableExperimentsByDefault(e){for(const t of e)this.checkExperiment(t),this.#r.add(t)}setServerEnabledExperiments(e){for(const t of e)this.checkExperiment(t),this.#s.add(t)}enableForTest(e){this.checkExperiment(e),this.#n.add(e)}disableForTest(e){this.checkExperiment(e),this.#n.delete(e)}clearForTest(){this.#e=[],this.#t.clear(),this.#n.clear(),this.#r.clear(),this.#s.clear()}cleanUpStaleExperiments(){this.#a.cleanUpStaleExperiments(this.#t)}checkExperiment(e){if(!this.#t.has(e))throw new Error(`Unknown experiment '${e}'`)}}class c{#e={};constructor(){try{const e=self.localStorage?.getItem("experiments");e&&(this.#e=JSON.parse(e))}catch{console.error("Failed to parse localStorage['experiments']")}}get(e){return this.#e[e]}set(e,t){this.#e[e]=t,this.#i()}cleanUpStaleExperiments(e){for(const[t]of Object.entries(this.#e))e.has(t)||delete this.#e[t];this.#i()}#i(){self.localStorage?.setItem("experiments",JSON.stringify(this.#e))}}class m{name;title;unstable;docLink;feedbackLink;#e;constructor(e,t,n,r,s,a){this.name=t,this.title=n,this.unstable=r,this.docLink=s,this.feedbackLink=a,this.#e=e}isEnabled(){return this.#e.isEnabled(this.name)}setEnabled(e){this.#e.setEnabled(this.name,e)}}const h=new l;var E,p,d,u;!function(e){e.REACT_NATIVE_SPECIFIC_UI="react-native-specific-ui",e.JS_HEAP_PROFILER_ENABLE="js-heap-profiler-enable",e.ENABLE_NETWORK_PANEL="enable-network-panel"}(E||(E={})),function(e){e.NOT_SOURCES_HIDE_ADD_FOLDER="!sources.hide_add_folder",e.REACT_NATIVE_UNSTABLE_NETWORK_PANEL="unstable_enableNetworkPanel"}(p||(p={})),function(e){e[e.ALLOW=0]="ALLOW",e[e.ALLOW_WITHOUT_LOGGING=1]="ALLOW_WITHOUT_LOGGING",e[e.DISABLE=2]="DISABLE"}(d||(d={})),function(e){e.ALL_SCRIPTS="ALL_SCRIPTS",e.SIDE_EFFECT_FREE_SCRIPTS_ONLY="SIDE_EFFECT_FREE_SCRIPTS_ONLY",e.NO_SCRIPTS="NO_SCRIPTS"}(u||(u={}));const _=Object.create(null),f={canDock:()=>Boolean(o.queryParam("can_dock")),notSourcesHideAddFolder:()=>Boolean(o.queryParam(p.NOT_SOURCES_HIDE_ADD_FOLDER)),reactNativeUnstableNetworkPanel:()=>Boolean(o.queryParam(p.REACT_NATIVE_UNSTABLE_NETWORK_PANEL))||h.isEnabled("enable-network-panel")};var x=Object.freeze({__proto__:null,get ConditionName(){return p},Experiment:m,ExperimentsSupport:l,get GenAiEnterprisePolicyValue(){return d},get HostConfigFreestylerExecutionMode(){return u},get RNExperimentName(){return E},Runtime:o,conditions:f,experiments:h,getChromeVersion:()=>{const e=navigator.userAgent.match(/(?:^|\W)(?:Chrome|HeadlessChrome)\/(\S+)/);return e&&e.length>1?e[1]:""},getPathName:a,getRemoteBase:function(e=self.location.toString()){const t=new URL(e).searchParams.get("remoteBase");if(!t)return null;const n=/\/serve_file\/(@[0-9a-zA-Z]+)\/?$/.exec(t);return n?{base:`devtools://devtools/remote/serve_file/${n[1]}/`,version:n[1]}:null},hostConfig:_,isNodeEntry:i});export{x as Runtime};
|
||||
|
||||
Vendored
+1
-1
File diff suppressed because one or more lines are too long
+1
-1
File diff suppressed because one or more lines are too long
+1
-1
File diff suppressed because one or more lines are too long
+1
-1
File diff suppressed because one or more lines are too long
+1
-1
File diff suppressed because one or more lines are too long
@@ -26,7 +26,9 @@ describe('console.timeStamp()', () => {
|
||||
|
||||
it("doesn't throw when additional arguments are specified", () => {
|
||||
expect(() =>
|
||||
console.timeStamp('label', 100, 500, 'Track', 'Group', 'error'),
|
||||
console.timeStamp('label', 100, 500, 'Track', 'Group', 'error', {
|
||||
tooltipText: 'Image processing failed',
|
||||
}),
|
||||
).not.toThrow();
|
||||
});
|
||||
|
||||
|
||||
@@ -30,8 +30,11 @@ class RCTDeviceEventEmitterImpl extends EventEmitter<RCTDeviceEventDefinitions>
|
||||
...args: RCTDeviceEventDefinitions[TEvent]
|
||||
): void {
|
||||
beginEvent(() => `RCTDeviceEventEmitter.emit#${eventType}`);
|
||||
super.emit(eventType, ...args);
|
||||
endEvent();
|
||||
try {
|
||||
super.emit(eventType, ...args);
|
||||
} finally {
|
||||
endEvent();
|
||||
}
|
||||
}
|
||||
}
|
||||
const RCTDeviceEventEmitter: IEventEmitter<RCTDeviceEventDefinitions> =
|
||||
|
||||
@@ -87,7 +87,7 @@ export default function Ansi({
|
||||
<View style={styles.container}>
|
||||
{parsedLines.map((items, i) => (
|
||||
<View style={styles.line} key={i}>
|
||||
<Text>
|
||||
<Text style={styles.text}>
|
||||
{items.map((bundle, key) => {
|
||||
const textStyle =
|
||||
bundle.fg && COLORS[bundle.fg]
|
||||
@@ -122,4 +122,7 @@ const styles = StyleSheet.create({
|
||||
line: {
|
||||
flexDirection: 'row',
|
||||
},
|
||||
text: {
|
||||
flexGrow: 1,
|
||||
},
|
||||
});
|
||||
|
||||
+1
-39
@@ -14,7 +14,6 @@ import type {
|
||||
EventCallback,
|
||||
EventListener,
|
||||
} from '../../src/private/webapis/dom/events/EventTarget';
|
||||
import type Performance from '../../src/private/webapis/performance/Performance';
|
||||
import type {IPerformanceLogger} from '../Utilities/createPerformanceLogger';
|
||||
|
||||
import Event from '../../src/private/webapis/dom/events/Event';
|
||||
@@ -34,13 +33,7 @@ const RCTNetworking = require('./RCTNetworking').default;
|
||||
const base64 = require('base64-js');
|
||||
const invariant = require('invariant');
|
||||
|
||||
const PERFORMANCE_TRACK_NAME = 'Network (JS-initiated only)';
|
||||
const PERFORMANCE_TRACK_GROUP = 'Chrome DevTools Temp Compat';
|
||||
|
||||
declare var performance: Performance;
|
||||
|
||||
const DEBUG_NETWORK_SEND_DELAY: false = false; // Set to a number of milliseconds when debugging
|
||||
const LABEL_FOR_MISSING_URL_FOR_PROFILING = 'Unknown URL';
|
||||
|
||||
export type NativeResponseType = 'base64' | 'blob' | 'text';
|
||||
export type ResponseType =
|
||||
@@ -141,7 +134,6 @@ class XMLHttpRequest extends EventTarget {
|
||||
static DONE: number = DONE;
|
||||
|
||||
static _interceptor: ?XHRInterceptor = null;
|
||||
static _profiling: boolean = false;
|
||||
|
||||
UNSENT: number = UNSENT;
|
||||
OPENED: number = OPENED;
|
||||
@@ -182,10 +174,6 @@ class XMLHttpRequest extends EventTarget {
|
||||
XMLHttpRequest._interceptor = interceptor;
|
||||
}
|
||||
|
||||
static enableProfiling(enableProfiling: boolean): void {
|
||||
XMLHttpRequest._profiling = enableProfiling;
|
||||
}
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
this._reset();
|
||||
@@ -389,23 +377,12 @@ class XMLHttpRequest extends EventTarget {
|
||||
return;
|
||||
}
|
||||
|
||||
const start = XMLHttpRequest._profiling ? performance.now() : undefined;
|
||||
|
||||
if (!this._response) {
|
||||
this._response = responseText;
|
||||
} else {
|
||||
this._response += responseText;
|
||||
}
|
||||
|
||||
if (XMLHttpRequest._profiling) {
|
||||
console.timeStamp(
|
||||
'Incremental Data: ' + this._getMeasureURL(),
|
||||
start,
|
||||
undefined,
|
||||
PERFORMANCE_TRACK_NAME,
|
||||
PERFORMANCE_TRACK_GROUP,
|
||||
);
|
||||
}
|
||||
XMLHttpRequest._interceptor &&
|
||||
XMLHttpRequest._interceptor.dataReceived(requestId, responseText);
|
||||
|
||||
@@ -450,16 +427,7 @@ class XMLHttpRequest extends EventTarget {
|
||||
this._clearSubscriptions();
|
||||
this._requestId = null;
|
||||
this.setReadyState(this.DONE);
|
||||
if (XMLHttpRequest._profiling && this._startTime != null) {
|
||||
const start = this._startTime;
|
||||
console.timeStamp(
|
||||
this._getMeasureURL(),
|
||||
start,
|
||||
undefined,
|
||||
PERFORMANCE_TRACK_NAME,
|
||||
PERFORMANCE_TRACK_GROUP,
|
||||
);
|
||||
}
|
||||
|
||||
if (error) {
|
||||
XMLHttpRequest._interceptor &&
|
||||
XMLHttpRequest._interceptor.loadingFailed(requestId, error);
|
||||
@@ -729,12 +697,6 @@ class XMLHttpRequest extends EventTarget {
|
||||
super.addEventListener(type, listener);
|
||||
}
|
||||
|
||||
_getMeasureURL(): string {
|
||||
return (
|
||||
this._trackingName ?? this._url ?? LABEL_FOR_MISSING_URL_FOR_PROFILING
|
||||
);
|
||||
}
|
||||
|
||||
/*
|
||||
* `on<event>` event handling (without JS prototype magic).
|
||||
*/
|
||||
|
||||
Vendored
-152
@@ -1,152 +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.
|
||||
*
|
||||
* @flow strict-local
|
||||
* @format
|
||||
*/
|
||||
|
||||
import type {
|
||||
HostInstance,
|
||||
MeasureInWindowOnSuccessCallback,
|
||||
MeasureLayoutOnSuccessCallback,
|
||||
MeasureOnSuccessCallback,
|
||||
NativeMethods,
|
||||
} from '../../../src/private/types/HostInstance';
|
||||
import type {
|
||||
InternalInstanceHandle,
|
||||
ViewConfig,
|
||||
} from '../../Renderer/shims/ReactNativeTypes';
|
||||
|
||||
import TextInputState from '../../Components/TextInput/TextInputState';
|
||||
import {getNodeFromInternalInstanceHandle} from '../../ReactNative/RendererProxy';
|
||||
import {getFabricUIManager} from '../FabricUIManager';
|
||||
import {create} from './ReactNativeAttributePayload';
|
||||
import warnForStyleProps from './warnForStyleProps';
|
||||
import nullthrows from 'nullthrows';
|
||||
|
||||
const {
|
||||
measure: fabricMeasure,
|
||||
measureInWindow: fabricMeasureInWindow,
|
||||
measureLayout: fabricMeasureLayout,
|
||||
getBoundingClientRect: fabricGetBoundingClientRect,
|
||||
setNativeProps,
|
||||
} = nullthrows(getFabricUIManager());
|
||||
|
||||
const noop = () => {};
|
||||
|
||||
/**
|
||||
* This is used for refs on host components.
|
||||
*/
|
||||
export default class ReactFabricHostComponent implements NativeMethods {
|
||||
// These need to be accessible from `ReactFabricPublicInstanceUtils`.
|
||||
__nativeTag: number;
|
||||
__internalInstanceHandle: InternalInstanceHandle;
|
||||
|
||||
_viewConfig: ViewConfig;
|
||||
|
||||
constructor(
|
||||
tag: number,
|
||||
viewConfig: ViewConfig,
|
||||
internalInstanceHandle: InternalInstanceHandle,
|
||||
) {
|
||||
this.__nativeTag = tag;
|
||||
this._viewConfig = viewConfig;
|
||||
this.__internalInstanceHandle = internalInstanceHandle;
|
||||
}
|
||||
|
||||
blur() {
|
||||
// $FlowFixMe[incompatible-type] - Error supressed during the migration of HostInstance to ReactNativeElement
|
||||
TextInputState.blurTextInput(this);
|
||||
}
|
||||
|
||||
focus() {
|
||||
// $FlowFixMe[incompatible-type] - Error supressed during the migration of HostInstance to ReactNativeElement
|
||||
TextInputState.focusTextInput(this);
|
||||
}
|
||||
|
||||
measure(callback: MeasureOnSuccessCallback) {
|
||||
const node = getNodeFromInternalInstanceHandle(
|
||||
this.__internalInstanceHandle,
|
||||
);
|
||||
if (node != null) {
|
||||
fabricMeasure(node, callback);
|
||||
}
|
||||
}
|
||||
|
||||
measureInWindow(callback: MeasureInWindowOnSuccessCallback) {
|
||||
const node = getNodeFromInternalInstanceHandle(
|
||||
this.__internalInstanceHandle,
|
||||
);
|
||||
if (node != null) {
|
||||
fabricMeasureInWindow(node, callback);
|
||||
}
|
||||
}
|
||||
|
||||
measureLayout(
|
||||
relativeToNativeNode: number | HostInstance,
|
||||
onSuccess: MeasureLayoutOnSuccessCallback,
|
||||
onFail?: () => void /* currently unused */,
|
||||
) {
|
||||
if (
|
||||
typeof relativeToNativeNode === 'number' ||
|
||||
!(relativeToNativeNode instanceof ReactFabricHostComponent)
|
||||
) {
|
||||
if (__DEV__) {
|
||||
console.error(
|
||||
'Warning: ref.measureLayout must be called with a ref to a native component.',
|
||||
);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
const toStateNode = getNodeFromInternalInstanceHandle(
|
||||
this.__internalInstanceHandle,
|
||||
);
|
||||
const fromStateNode = getNodeFromInternalInstanceHandle(
|
||||
relativeToNativeNode.__internalInstanceHandle,
|
||||
);
|
||||
|
||||
if (toStateNode != null && fromStateNode != null) {
|
||||
fabricMeasureLayout(
|
||||
toStateNode,
|
||||
fromStateNode,
|
||||
onFail != null ? onFail : noop,
|
||||
onSuccess != null ? onSuccess : noop,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
unstable_getBoundingClientRect(): DOMRect {
|
||||
const node = getNodeFromInternalInstanceHandle(
|
||||
this.__internalInstanceHandle,
|
||||
);
|
||||
if (node != null) {
|
||||
const rect = fabricGetBoundingClientRect(node, true);
|
||||
|
||||
if (rect) {
|
||||
return new DOMRect(rect[0], rect[1], rect[2], rect[3]);
|
||||
}
|
||||
}
|
||||
|
||||
// Empty rect if any of the above failed
|
||||
return new DOMRect(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
setNativeProps(nativeProps: {...}): void {
|
||||
if (__DEV__) {
|
||||
warnForStyleProps(nativeProps, this._viewConfig.validAttributes);
|
||||
}
|
||||
const updatePayload = create(nativeProps, this._viewConfig.validAttributes);
|
||||
|
||||
const node = getNodeFromInternalInstanceHandle(
|
||||
this.__internalInstanceHandle,
|
||||
);
|
||||
if (node != null && updatePayload != null) {
|
||||
setNativeProps(node, updatePayload);
|
||||
}
|
||||
}
|
||||
}
|
||||
Vendored
+20
-82
@@ -13,124 +13,62 @@
|
||||
* instances and get some data from them (like their instance handle / fiber).
|
||||
*/
|
||||
|
||||
import type ReactNativeDocumentT from '../../../src/private/webapis/dom/nodes/ReactNativeDocument';
|
||||
import typeof * as ReactNativeDocumentModuleT from '../../../src/private/webapis/dom/nodes/ReactNativeDocument';
|
||||
import type ReactNativeElementT from '../../../src/private/webapis/dom/nodes/ReactNativeElement';
|
||||
import type ReadOnlyTextT from '../../../src/private/webapis/dom/nodes/ReadOnlyText';
|
||||
import typeof * as RendererProxyT from '../../ReactNative/RendererProxy';
|
||||
import type {
|
||||
InternalInstanceHandle,
|
||||
Node,
|
||||
ViewConfig,
|
||||
} from '../../Renderer/shims/ReactNativeTypes';
|
||||
import type {RootTag} from '../RootTag';
|
||||
import type ReactFabricHostComponentT from './ReactFabricHostComponent';
|
||||
|
||||
import * as ReactNativeFeatureFlags from '../../../src/private/featureflags/ReactNativeFeatureFlags';
|
||||
import ReactNativeDocument, {
|
||||
createReactNativeDocument,
|
||||
} from '../../../src/private/webapis/dom/nodes/ReactNativeDocument';
|
||||
import ReactNativeElement from '../../../src/private/webapis/dom/nodes/ReactNativeElement';
|
||||
import ReadOnlyText from '../../../src/private/webapis/dom/nodes/ReadOnlyText';
|
||||
import * as RendererProxy from '../../ReactNative/RendererProxy';
|
||||
|
||||
export opaque type PublicRootInstance = mixed;
|
||||
|
||||
// Lazy loaded to avoid evaluating the module when using the legacy renderer.
|
||||
let ReactNativeDocumentModuleObject: ?ReactNativeDocumentModuleT;
|
||||
let ReactFabricHostComponentClass: Class<ReactFabricHostComponentT>;
|
||||
let ReactNativeElementClass: Class<ReactNativeElementT>;
|
||||
let ReadOnlyTextClass: Class<ReadOnlyTextT>;
|
||||
let RendererProxy: RendererProxyT;
|
||||
|
||||
function getReactNativeDocumentModule(): ReactNativeDocumentModuleT {
|
||||
if (ReactNativeDocumentModuleObject == null) {
|
||||
// We initialize this lazily to avoid a require cycle.
|
||||
ReactNativeDocumentModuleObject = require('../../../src/private/webapis/dom/nodes/ReactNativeDocument');
|
||||
}
|
||||
|
||||
return ReactNativeDocumentModuleObject;
|
||||
}
|
||||
|
||||
function getReactNativeElementClass(): Class<ReactNativeElementT> {
|
||||
if (ReactNativeElementClass == null) {
|
||||
ReactNativeElementClass =
|
||||
require('../../../src/private/webapis/dom/nodes/ReactNativeElement').default;
|
||||
}
|
||||
return ReactNativeElementClass;
|
||||
}
|
||||
|
||||
function getReactFabricHostComponentClass(): Class<ReactFabricHostComponentT> {
|
||||
if (ReactFabricHostComponentClass == null) {
|
||||
ReactFabricHostComponentClass =
|
||||
require('./ReactFabricHostComponent').default;
|
||||
}
|
||||
return ReactFabricHostComponentClass;
|
||||
}
|
||||
|
||||
function getReadOnlyTextClass(): Class<ReadOnlyTextT> {
|
||||
if (ReadOnlyTextClass == null) {
|
||||
ReadOnlyTextClass =
|
||||
require('../../../src/private/webapis/dom/nodes/ReadOnlyText').default;
|
||||
}
|
||||
return ReadOnlyTextClass;
|
||||
}
|
||||
|
||||
export function createPublicRootInstance(rootTag: RootTag): PublicRootInstance {
|
||||
if (ReactNativeFeatureFlags.enableAccessToHostTreeInFabric()) {
|
||||
const ReactNativeDocumentModule = getReactNativeDocumentModule();
|
||||
|
||||
// $FlowExpectedError[incompatible-return]
|
||||
return ReactNativeDocumentModule.createReactNativeDocument(rootTag);
|
||||
}
|
||||
|
||||
// $FlowExpectedError[incompatible-return]
|
||||
return null;
|
||||
return createReactNativeDocument(rootTag);
|
||||
}
|
||||
|
||||
export function createPublicInstance(
|
||||
tag: number,
|
||||
viewConfig: ViewConfig,
|
||||
internalInstanceHandle: InternalInstanceHandle,
|
||||
ownerDocument: ReactNativeDocumentT,
|
||||
): ReactFabricHostComponentT | ReactNativeElementT {
|
||||
if (ReactNativeFeatureFlags.enableAccessToHostTreeInFabric()) {
|
||||
const ReactNativeElement = getReactNativeElementClass();
|
||||
return new ReactNativeElement(
|
||||
tag,
|
||||
viewConfig,
|
||||
internalInstanceHandle,
|
||||
ownerDocument,
|
||||
);
|
||||
} else {
|
||||
const ReactFabricHostComponent = getReactFabricHostComponentClass();
|
||||
return new ReactFabricHostComponent(
|
||||
tag,
|
||||
viewConfig,
|
||||
internalInstanceHandle,
|
||||
);
|
||||
}
|
||||
ownerDocument: ReactNativeDocument,
|
||||
): ReactNativeElement {
|
||||
return new ReactNativeElement(
|
||||
tag,
|
||||
viewConfig,
|
||||
internalInstanceHandle,
|
||||
ownerDocument,
|
||||
);
|
||||
}
|
||||
|
||||
export function createPublicTextInstance(
|
||||
internalInstanceHandle: InternalInstanceHandle,
|
||||
ownerDocument: ReactNativeDocumentT,
|
||||
): ReadOnlyTextT {
|
||||
const ReadOnlyText = getReadOnlyTextClass();
|
||||
ownerDocument: ReactNativeDocument,
|
||||
): ReadOnlyText {
|
||||
return new ReadOnlyText(internalInstanceHandle, ownerDocument);
|
||||
}
|
||||
|
||||
export function getNativeTagFromPublicInstance(
|
||||
publicInstance: ReactFabricHostComponentT | ReactNativeElementT,
|
||||
publicInstance: ReactNativeElement,
|
||||
): number {
|
||||
return publicInstance.__nativeTag;
|
||||
}
|
||||
|
||||
export function getNodeFromPublicInstance(
|
||||
publicInstance: ReactFabricHostComponentT | ReactNativeElementT,
|
||||
publicInstance: ReactNativeElement,
|
||||
): ?Node {
|
||||
// Avoid loading ReactFabric if using an instance from the legacy renderer.
|
||||
if (publicInstance.__internalInstanceHandle == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (RendererProxy == null) {
|
||||
RendererProxy = require('../../ReactNative/RendererProxy');
|
||||
}
|
||||
return RendererProxy.getNodeFromInternalInstanceHandle(
|
||||
// $FlowExpectedError[incompatible-type] __internalInstanceHandle is always an InternalInstanceHandle from React when we get here.
|
||||
publicInstance.__internalInstanceHandle,
|
||||
@@ -138,7 +76,7 @@ export function getNodeFromPublicInstance(
|
||||
}
|
||||
|
||||
export function getInternalInstanceHandleFromPublicInstance(
|
||||
publicInstance: ReactFabricHostComponentT | ReactNativeElementT,
|
||||
publicInstance: ReactNativeElement,
|
||||
): InternalInstanceHandle {
|
||||
// TODO(T174762768): Remove this once OSS versions of renderers will be synced.
|
||||
// $FlowExpectedError[prop-missing] Keeping this for backwards-compatibility with the renderers versions in open source.
|
||||
|
||||
-75
@@ -1,75 +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.
|
||||
*
|
||||
* @flow strict-local
|
||||
* @format
|
||||
*/
|
||||
|
||||
import '@react-native/fantom/src/setUpDefaultReactNativeEnvironment';
|
||||
|
||||
import type {
|
||||
InternalInstanceHandle,
|
||||
ViewConfig,
|
||||
} from 'react-native/Libraries/Renderer/shims/ReactNativeTypes';
|
||||
import type ReactNativeDocument from 'react-native/src/private/webapis/dom/nodes/ReactNativeDocument';
|
||||
|
||||
import * as Fantom from '@react-native/fantom';
|
||||
import ReactFabricHostComponent from 'react-native/Libraries/ReactNative/ReactFabricPublicInstance/ReactFabricHostComponent';
|
||||
import ReactNativeElement from 'react-native/src/private/webapis/dom/nodes/ReactNativeElement';
|
||||
|
||||
// Create fake parameters for the class.
|
||||
const tag = 11;
|
||||
const viewConfig: ViewConfig = {
|
||||
uiViewClassName: 'test',
|
||||
validAttributes: {
|
||||
style: {},
|
||||
},
|
||||
};
|
||||
// $FlowExpectedError[incompatible-type]
|
||||
const internalInstanceHandle: InternalInstanceHandle = {};
|
||||
// $FlowExpectedError[incompatible-type]
|
||||
const ownerDocument: ReactNativeDocument = {};
|
||||
|
||||
const ITERATIONS = 100;
|
||||
|
||||
const now = Fantom.unstable_benchmark.now;
|
||||
|
||||
/* eslint-disable no-new */
|
||||
Fantom.unstable_benchmark
|
||||
.suite('ReactNativeElement vs. ReactFabricHostComponent', {
|
||||
minIterations: 50000,
|
||||
})
|
||||
.test('ReactNativeElement', () => {
|
||||
// This logic is very fast and if we only run it once the cost of calling
|
||||
// the benchmark function itself is significant. Calling it in a loop and
|
||||
// computing the average is more accurate to account for that.
|
||||
const start = now();
|
||||
for (let i = 0; i < ITERATIONS; i++) {
|
||||
new ReactNativeElement(
|
||||
tag,
|
||||
viewConfig,
|
||||
internalInstanceHandle,
|
||||
ownerDocument,
|
||||
);
|
||||
}
|
||||
const end = now();
|
||||
return {
|
||||
overriddenDuration: (end - start) / ITERATIONS,
|
||||
};
|
||||
})
|
||||
.test('ReactFabricHostComponent', () => {
|
||||
// This logic is very fast and if we only run it once the cost of calling
|
||||
// the benchmark function itself is significant. Calling it in a loop and
|
||||
// computing the average is more accurate to account for that.
|
||||
const start = now();
|
||||
for (let i = 0; i < ITERATIONS; i++) {
|
||||
new ReactFabricHostComponent(tag, viewConfig, internalInstanceHandle);
|
||||
}
|
||||
const end = now();
|
||||
return {
|
||||
overriddenDuration: (end - start) / ITERATIONS,
|
||||
};
|
||||
});
|
||||
-353
@@ -1,353 +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.
|
||||
*
|
||||
* @flow strict-local
|
||||
* @format
|
||||
* @fantom_flags enableAccessToHostTreeInFabric:*
|
||||
*/
|
||||
|
||||
import '@react-native/fantom/src/setUpDefaultReactNativeEnvironment';
|
||||
|
||||
import type {HostInstance} from 'react-native';
|
||||
|
||||
import ReactNativeElement from '../../../../src/private/webapis/dom/nodes/ReactNativeElement';
|
||||
import TextInput from '../../../Components/TextInput/TextInput';
|
||||
import TextInputState from '../../../Components/TextInput/TextInputState';
|
||||
import View from '../../../Components/View/View';
|
||||
import ReactFabricHostComponent from '../ReactFabricHostComponent';
|
||||
import * as Fantom from '@react-native/fantom';
|
||||
import nullthrows from 'nullthrows';
|
||||
import * as React from 'react';
|
||||
import {createRef} from 'react';
|
||||
import * as ReactNativeFeatureFlags from 'react-native/src/private/featureflags/ReactNativeFeatureFlags';
|
||||
|
||||
// TODO: move these tests to the test file for `ReactNativeElement` when the legacy implementation is removed.
|
||||
describe('ReactFabricPublicInstance', () => {
|
||||
it('should provide instances of the right class as refs in host components', () => {
|
||||
const nodeRef = createRef<HostInstance>();
|
||||
|
||||
const root = Fantom.createRoot();
|
||||
Fantom.runTask(() => {
|
||||
root.render(<View ref={nodeRef} />);
|
||||
});
|
||||
|
||||
const node = nullthrows(nodeRef.current);
|
||||
|
||||
expect(node).toBeInstanceOf(
|
||||
ReactNativeFeatureFlags.enableAccessToHostTreeInFabric()
|
||||
? ReactNativeElement
|
||||
: ReactFabricHostComponent,
|
||||
);
|
||||
});
|
||||
|
||||
describe('blur', () => {
|
||||
test('blur() invokes TextInputState', () => {
|
||||
const root = Fantom.createRoot();
|
||||
const nodeRef = createRef<HostInstance>();
|
||||
|
||||
Fantom.runTask(() => {
|
||||
root.render(<TextInput ref={nodeRef} />);
|
||||
});
|
||||
|
||||
const node = nullthrows(nodeRef.current);
|
||||
|
||||
const blurTextInput = jest.fn();
|
||||
|
||||
// We don't support view commands in Fantom yet, so we have to mock this.
|
||||
TextInputState.blurTextInput = blurTextInput;
|
||||
|
||||
Fantom.runTask(() => {
|
||||
node.blur();
|
||||
});
|
||||
|
||||
expect(blurTextInput).toHaveBeenCalledTimes(1);
|
||||
expect(blurTextInput.mock.calls).toEqual([[node]]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('focus', () => {
|
||||
test('focus() invokes TextInputState', () => {
|
||||
const root = Fantom.createRoot();
|
||||
const ref = createRef<HostInstance>();
|
||||
|
||||
Fantom.runTask(() => {
|
||||
root.render(<TextInput ref={ref} />);
|
||||
});
|
||||
|
||||
const node = nullthrows(ref.current);
|
||||
|
||||
const focusTextInput = jest.fn();
|
||||
|
||||
// We don't support view commands in Fantom yet, so we have to mock this.
|
||||
TextInputState.focusTextInput = focusTextInput;
|
||||
|
||||
Fantom.runTask(() => {
|
||||
node.focus();
|
||||
});
|
||||
|
||||
expect(focusTextInput).toHaveBeenCalledTimes(1);
|
||||
expect(focusTextInput.mock.calls).toEqual([[node]]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('measure', () => {
|
||||
it('component.measure(...) invokes callback', () => {
|
||||
const root = Fantom.createRoot();
|
||||
const ref = createRef<HostInstance>();
|
||||
|
||||
Fantom.runTask(() => {
|
||||
root.render(
|
||||
<View
|
||||
style={{width: 100, height: 100, left: 10, top: 10}}
|
||||
ref={ref}
|
||||
/>,
|
||||
);
|
||||
});
|
||||
|
||||
const node = nullthrows(ref.current);
|
||||
|
||||
const callback = jest.fn();
|
||||
node.measure(callback);
|
||||
|
||||
expect(callback).toHaveBeenCalledTimes(1);
|
||||
expect(callback.mock.calls).toEqual([[10, 10, 100, 100, 10, 10]]);
|
||||
});
|
||||
|
||||
it('unmounted.measure(...) does nothing', () => {
|
||||
const root = Fantom.createRoot();
|
||||
const ref = createRef<HostInstance>();
|
||||
|
||||
Fantom.runTask(() => {
|
||||
root.render(
|
||||
<View
|
||||
style={{width: 100, height: 100, left: 10, top: 10}}
|
||||
ref={ref}
|
||||
/>,
|
||||
);
|
||||
});
|
||||
|
||||
const node = nullthrows(ref.current);
|
||||
|
||||
Fantom.runTask(() => {
|
||||
root.render(<></>);
|
||||
});
|
||||
|
||||
const callback = jest.fn();
|
||||
node.measure(callback);
|
||||
|
||||
expect(callback).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe('measureInWindow', () => {
|
||||
it('component.measureInWindow(...) invokes callback', () => {
|
||||
const root = Fantom.createRoot();
|
||||
const ref = createRef<HostInstance>();
|
||||
|
||||
Fantom.runTask(() => {
|
||||
root.render(
|
||||
<View
|
||||
style={{width: 100, height: 100, left: 10, top: 10}}
|
||||
ref={ref}
|
||||
/>,
|
||||
);
|
||||
});
|
||||
|
||||
const node = nullthrows(ref.current);
|
||||
|
||||
const callback = jest.fn();
|
||||
node.measureInWindow(callback);
|
||||
|
||||
expect(callback).toHaveBeenCalledTimes(1);
|
||||
expect(callback.mock.calls).toEqual([[10, 10, 100, 100]]);
|
||||
});
|
||||
|
||||
it('unmounted.measureInWindow(...) does nothing', () => {
|
||||
const root = Fantom.createRoot();
|
||||
const ref = createRef<HostInstance>();
|
||||
|
||||
Fantom.runTask(() => {
|
||||
root.render(
|
||||
<View
|
||||
style={{width: 100, height: 100, left: 10, top: 10}}
|
||||
ref={ref}
|
||||
/>,
|
||||
);
|
||||
});
|
||||
|
||||
const node = nullthrows(ref.current);
|
||||
|
||||
Fantom.runTask(() => {
|
||||
root.render(<></>);
|
||||
});
|
||||
|
||||
const callback = jest.fn();
|
||||
node.measureInWindow(callback);
|
||||
|
||||
expect(callback).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe('measureLayout', () => {
|
||||
it('component.measureLayout(component, ...) invokes callback', () => {
|
||||
const root = Fantom.createRoot();
|
||||
const parentRef = createRef<HostInstance>();
|
||||
const childRef = createRef<HostInstance>();
|
||||
|
||||
Fantom.runTask(() => {
|
||||
root.render(
|
||||
<View
|
||||
style={{width: 100, height: 100, left: 10, top: 10}}
|
||||
ref={parentRef}>
|
||||
<View
|
||||
style={{width: 10, height: 10, left: 20, top: 20}}
|
||||
ref={childRef}
|
||||
/>
|
||||
</View>,
|
||||
);
|
||||
});
|
||||
|
||||
const parentNode = nullthrows(parentRef.current);
|
||||
const childNode = nullthrows(childRef.current);
|
||||
|
||||
const callback = jest.fn();
|
||||
childNode.measureLayout(parentNode, callback);
|
||||
|
||||
expect(callback).toHaveBeenCalledTimes(1);
|
||||
expect(callback.mock.calls).toEqual([[20, 20, 10, 10]]);
|
||||
});
|
||||
|
||||
it('unmounted.measureLayout(component, ...) does nothing', () => {
|
||||
const root = Fantom.createRoot();
|
||||
const parentRef = createRef<HostInstance>();
|
||||
const childRef = createRef<HostInstance>();
|
||||
|
||||
Fantom.runTask(() => {
|
||||
root.render(
|
||||
<View
|
||||
style={{width: 100, height: 100, left: 10, top: 10}}
|
||||
ref={parentRef}>
|
||||
<View
|
||||
style={{width: 10, height: 10, left: 20, top: 20}}
|
||||
ref={childRef}
|
||||
/>
|
||||
</View>,
|
||||
);
|
||||
});
|
||||
|
||||
const parentNode = nullthrows(parentRef.current);
|
||||
const childNode = nullthrows(childRef.current);
|
||||
|
||||
Fantom.runTask(() => {
|
||||
root.render(
|
||||
<View style={{width: 100, height: 100, left: 10, top: 10}} />,
|
||||
);
|
||||
});
|
||||
|
||||
const callback = jest.fn();
|
||||
childNode.measureLayout(parentNode, callback);
|
||||
|
||||
expect(callback).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('component.measureLayout(unmounted, ...) does nothing', () => {
|
||||
const root = Fantom.createRoot();
|
||||
const parentRef = createRef<HostInstance>();
|
||||
const childRef = createRef<HostInstance>();
|
||||
|
||||
Fantom.runTask(() => {
|
||||
root.render(
|
||||
<View
|
||||
style={{width: 100, height: 100, left: 10, top: 10}}
|
||||
ref={parentRef}>
|
||||
<View
|
||||
style={{width: 10, height: 10, left: 20, top: 20}}
|
||||
ref={childRef}
|
||||
/>
|
||||
</View>,
|
||||
);
|
||||
});
|
||||
|
||||
const parentNode = nullthrows(parentRef.current);
|
||||
const childNode = nullthrows(childRef.current);
|
||||
|
||||
Fantom.runTask(() => {
|
||||
root.render(
|
||||
<View style={{width: 100, height: 100, left: 10, top: 10}} />,
|
||||
);
|
||||
});
|
||||
|
||||
const callback = jest.fn();
|
||||
parentNode.measureLayout(childNode, callback);
|
||||
|
||||
expect(callback).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('unmounted.measureLayout(unmounted, ...) does nothing', () => {
|
||||
const root = Fantom.createRoot();
|
||||
const parentRef = createRef<HostInstance>();
|
||||
const childRef = createRef<HostInstance>();
|
||||
|
||||
Fantom.runTask(() => {
|
||||
root.render(
|
||||
<View
|
||||
style={{width: 100, height: 100, left: 10, top: 10}}
|
||||
ref={parentRef}>
|
||||
<View
|
||||
style={{width: 10, height: 10, left: 20, top: 20}}
|
||||
ref={childRef}
|
||||
/>
|
||||
</View>,
|
||||
);
|
||||
});
|
||||
|
||||
const parentNode = nullthrows(parentRef.current);
|
||||
const childNode = nullthrows(childRef.current);
|
||||
|
||||
Fantom.runTask(() => {
|
||||
root.render(<></>);
|
||||
});
|
||||
|
||||
const callback = jest.fn();
|
||||
childNode.measureLayout(parentNode, callback);
|
||||
|
||||
expect(callback).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe('setNativeProps', () => {
|
||||
it('should propagate changes to the host component', () => {
|
||||
const root = Fantom.createRoot();
|
||||
const nodeRef = createRef<HostInstance>();
|
||||
|
||||
Fantom.runTask(() => {
|
||||
root.render(<View ref={nodeRef} testID="first test id" />);
|
||||
});
|
||||
|
||||
expect(
|
||||
root
|
||||
.getRenderedOutput({
|
||||
props: ['testID'],
|
||||
})
|
||||
.toJSX(),
|
||||
).toEqual(<rn-view testID={'first test id'} />);
|
||||
|
||||
const element = nullthrows(nodeRef.current);
|
||||
|
||||
Fantom.runTask(() => {
|
||||
element.setNativeProps({testID: 'second test id'});
|
||||
});
|
||||
|
||||
expect(
|
||||
root
|
||||
.getRenderedOutput({
|
||||
props: ['testID'],
|
||||
})
|
||||
.toJSX(),
|
||||
).toEqual(<rn-view testID={'second test id'} />);
|
||||
});
|
||||
});
|
||||
});
|
||||
+12
-1
@@ -1088,6 +1088,16 @@ static RCTBorderStyle RCTBorderStyleFromOutlineStyle(OutlineStyle outlineStyle)
|
||||
Float saturation = std::get<Float>(primitive.parameters);
|
||||
[_swiftUIWrapper updateSaturation:@(saturation)];
|
||||
}
|
||||
} else if (primitive.type == FilterType::Contrast) {
|
||||
if (_swiftUIWrapper != nullptr) {
|
||||
Float contrast = std::get<Float>(primitive.parameters);
|
||||
[_swiftUIWrapper updateContrast:@(contrast)];
|
||||
}
|
||||
} else if (primitive.type == FilterType::HueRotate) {
|
||||
if (_swiftUIWrapper != nullptr) {
|
||||
Float hueRotateDegrees = std::get<Float>(primitive.parameters);
|
||||
[_swiftUIWrapper updateHueRotate:@(hueRotateDegrees)];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1545,7 +1555,8 @@ static NSString *RCTRecursiveAccessibilityLabel(UIView *view)
|
||||
if (!_props->filter.empty()) {
|
||||
for (const auto &primitive : _props->filter) {
|
||||
if (primitive.type == FilterType::Blur || primitive.type == FilterType::Grayscale ||
|
||||
primitive.type == FilterType::DropShadow || primitive.type == FilterType::Saturate) {
|
||||
primitive.type == FilterType::DropShadow || primitive.type == FilterType::Saturate ||
|
||||
primitive.type == FilterType::Contrast || primitive.type == FilterType::HueRotate) {
|
||||
return YES;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -247,8 +247,12 @@ static UIImage *RCTGetSolidBorderImage(
|
||||
|
||||
const CGSize size = makeStretchable ? (CGSize){
|
||||
// 1pt for the middle stretchable area along each axis
|
||||
edgeInsets.left + 1 + edgeInsets.right,
|
||||
edgeInsets.top + 1 + edgeInsets.bottom
|
||||
// we also need to round the edge insets to avoid border bleeding
|
||||
// this is because if the size is decimal, when calculating the unit
|
||||
// rectangle for CALayer.contentsCenter we encounter rounding errors
|
||||
// which causes visual glitches
|
||||
ceil(edgeInsets.left) + 1 + ceil(edgeInsets.right),
|
||||
ceil(edgeInsets.top) + 1 + ceil(edgeInsets.bottom),
|
||||
} : viewSize;
|
||||
|
||||
UIGraphicsImageRenderer *const imageRenderer =
|
||||
|
||||
@@ -5651,6 +5651,7 @@ public class com/facebook/react/views/scroll/ReactHorizontalScrollView : android
|
||||
public fun pageScroll (I)Z
|
||||
public fun reactSmoothScrollTo (II)V
|
||||
public fun requestChildFocus (Landroid/view/View;Landroid/view/View;)V
|
||||
protected fun requestChildFocusWithoutScroll (Landroid/view/View;Landroid/view/View;)V
|
||||
protected fun restoreScrollTo (II)V
|
||||
public fun scrollTo (II)V
|
||||
public fun scrollToPreservingMomentum (II)V
|
||||
@@ -5791,6 +5792,7 @@ public class com/facebook/react/views/scroll/ReactScrollView : android/widget/Sc
|
||||
public fun onTouchEvent (Landroid/view/MotionEvent;)Z
|
||||
public fun reactSmoothScrollTo (II)V
|
||||
public fun requestChildFocus (Landroid/view/View;Landroid/view/View;)V
|
||||
protected fun requestChildFocusWithoutScroll (Landroid/view/View;Landroid/view/View;)V
|
||||
public fun scrollTo (II)V
|
||||
public fun scrollToPreservingMomentum (II)V
|
||||
public fun setBackgroundColor (I)V
|
||||
|
||||
+12
@@ -22,6 +22,7 @@ internal class PerfMonitorOverlayManager(
|
||||
|
||||
private var view: PerfMonitorOverlayView? = null
|
||||
private var tracingState: TracingState = TracingState.ENABLEDINCDPMODE
|
||||
private var perfIssueCount: Int = 0
|
||||
|
||||
/** Enable the Perf Monitor overlay. */
|
||||
fun enable() {
|
||||
@@ -72,8 +73,19 @@ internal class PerfMonitorOverlayManager(
|
||||
|
||||
override fun onRecordingStateChanged(state: TracingState) {
|
||||
tracingState = state
|
||||
if (state != TracingState.DISABLED) {
|
||||
perfIssueCount = 0
|
||||
}
|
||||
UiThreadUtil.runOnUiThread {
|
||||
view?.updateRecordingState(state)
|
||||
view?.updatePerfIssueCount(perfIssueCount)
|
||||
view?.show()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onPerfIssueAdded(name: String) {
|
||||
UiThreadUtil.runOnUiThread {
|
||||
view?.updatePerfIssueCount(++perfIssueCount)
|
||||
view?.show()
|
||||
}
|
||||
}
|
||||
|
||||
+35
-7
@@ -30,9 +30,11 @@ internal class PerfMonitorOverlayView(
|
||||
private val onButtonPress: () -> Unit,
|
||||
) {
|
||||
private val dialog: Dialog
|
||||
private lateinit var statusIndicator: TextView
|
||||
private lateinit var statusLabel: TextView
|
||||
private lateinit var tooltipLabel: TextView
|
||||
private lateinit var statusIndicator: TextView
|
||||
private lateinit var issuesContainer: LinearLayout
|
||||
private lateinit var issueCountLabel: TextView
|
||||
|
||||
init {
|
||||
DisplayMetricsHolder.initDisplayMetricsIfNotInitialized(context)
|
||||
@@ -70,6 +72,11 @@ internal class PerfMonitorOverlayView(
|
||||
dialog.show()
|
||||
}
|
||||
|
||||
fun updatePerfIssueCount(count: Int) {
|
||||
issueCountLabel.text = count.toString()
|
||||
issuesContainer.visibility = if (count == 0) LinearLayout.GONE else LinearLayout.VISIBLE
|
||||
}
|
||||
|
||||
private fun createToolbarDialog(): Dialog {
|
||||
statusIndicator =
|
||||
TextView(context).apply {
|
||||
@@ -85,11 +92,7 @@ internal class PerfMonitorOverlayView(
|
||||
val textContainer =
|
||||
LinearLayout(context).apply {
|
||||
orientation = LinearLayout.VERTICAL
|
||||
layoutParams =
|
||||
LinearLayout.LayoutParams(
|
||||
LinearLayout.LayoutParams.WRAP_CONTENT,
|
||||
LinearLayout.LayoutParams.WRAP_CONTENT,
|
||||
)
|
||||
setPadding(dpToPx(2f).toInt(), 0, 0, 0)
|
||||
}
|
||||
statusLabel =
|
||||
TextView(context).apply {
|
||||
@@ -106,10 +109,35 @@ internal class PerfMonitorOverlayView(
|
||||
textContainer.addView(statusLabel)
|
||||
textContainer.addView(tooltipLabel)
|
||||
|
||||
issuesContainer =
|
||||
LinearLayout(context).apply {
|
||||
setPadding(dpToPx(8f).toInt(), 0, 0, 0)
|
||||
visibility = LinearLayout.GONE
|
||||
}
|
||||
issueCountLabel =
|
||||
TextView(context).apply {
|
||||
textSize = TEXT_SIZE_PRIMARY
|
||||
setTextColor(Color.WHITE)
|
||||
typeface = TYPEFACE_BOLD
|
||||
val alertDrawable =
|
||||
context.getDrawable(android.R.drawable.ic_dialog_alert)?.apply {
|
||||
setBounds(
|
||||
0,
|
||||
1,
|
||||
dpToPx(TEXT_SIZE_PRIMARY).toInt(),
|
||||
dpToPx(TEXT_SIZE_PRIMARY).toInt() + 1,
|
||||
)
|
||||
}
|
||||
setCompoundDrawables(alertDrawable, null, null, null)
|
||||
compoundDrawablePadding = dpToPx(6f).toInt()
|
||||
}
|
||||
issuesContainer.addView(issueCountLabel)
|
||||
|
||||
val containerLayout = createInnerLayout()
|
||||
containerLayout.setOnClickListener { onButtonPress() }
|
||||
containerLayout.addView(statusIndicator)
|
||||
containerLayout.addView(textContainer)
|
||||
containerLayout.addView(issuesContainer)
|
||||
|
||||
val dialog =
|
||||
createAnchoredDialog(dpToPx(12f), dpToPx(12f)).apply { setContentView(containerLayout) }
|
||||
@@ -175,7 +203,7 @@ internal class PerfMonitorOverlayView(
|
||||
showDividers = LinearLayout.SHOW_DIVIDER_MIDDLE
|
||||
dividerDrawable =
|
||||
object : ColorDrawable(Color.TRANSPARENT) {
|
||||
override fun getIntrinsicWidth(): Int = dpToPx(8f).toInt()
|
||||
override fun getIntrinsicWidth(): Int = dpToPx(10f).toInt()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+4
@@ -4,6 +4,7 @@
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
package com.facebook.react.devsupport.perfmonitor
|
||||
|
||||
import com.facebook.react.devsupport.interfaces.TracingState
|
||||
@@ -12,4 +13,7 @@ import com.facebook.react.devsupport.interfaces.TracingState
|
||||
internal interface PerfMonitorUpdateListener {
|
||||
/** Called when the recording state of the background performance trace has changed. */
|
||||
fun onRecordingStateChanged(state: TracingState)
|
||||
|
||||
/** Called when a new Performance Issue is added. */
|
||||
fun onPerfIssueAdded(name: String)
|
||||
}
|
||||
|
||||
+1
-4
@@ -80,7 +80,7 @@ public class SurfaceMountingManager {
|
||||
// These are all non-null, until StopSurface is called
|
||||
private ConcurrentHashMap<Integer, ViewState> mTagToViewState =
|
||||
new ConcurrentHashMap<>(); // any thread
|
||||
private Queue<MountItem> mOnViewAttachMountItems = new ArrayDeque<>();
|
||||
private final Queue<MountItem> mOnViewAttachMountItems = new ArrayDeque<>();
|
||||
private JSResponderHandler mJSResponderHandler;
|
||||
private ViewManagerRegistry mViewManagerRegistry;
|
||||
private RootViewManager mRootViewManager;
|
||||
@@ -1344,7 +1344,6 @@ public class SurfaceMountingManager {
|
||||
final boolean mIsRoot;
|
||||
@Nullable ViewManager mViewManager = null;
|
||||
@Nullable ReactStylesDiffMap mCurrentProps = null;
|
||||
@Nullable ReadableMap mCurrentLocalData = null;
|
||||
@Nullable StateWrapper mStateWrapper = null;
|
||||
@Nullable EventEmitterWrapper mEventEmitter = null;
|
||||
|
||||
@@ -1374,8 +1373,6 @@ public class SurfaceMountingManager {
|
||||
+ mIsRoot
|
||||
+ " - props: "
|
||||
+ mCurrentProps
|
||||
+ " - localData: "
|
||||
+ mCurrentLocalData
|
||||
+ " - viewManager: "
|
||||
+ mViewManager
|
||||
+ " - isLayoutOnly: "
|
||||
|
||||
+19
-1
@@ -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<<28000f9d4a36207875619060f2fa5713>>
|
||||
* @generated SignedSource<<d8dc8c3a2efe8b7e870546e5749ef5ad>>
|
||||
*/
|
||||
|
||||
/**
|
||||
@@ -210,6 +210,12 @@ public object ReactNativeFeatureFlags {
|
||||
@JvmStatic
|
||||
public fun enableInteropViewManagerClassLookUpOptimizationIOS(): Boolean = accessor.enableInteropViewManagerClassLookUpOptimizationIOS()
|
||||
|
||||
/**
|
||||
* Enables key up/down/press events to be sent to JS from components
|
||||
*/
|
||||
@JvmStatic
|
||||
public fun enableKeyEvents(): Boolean = accessor.enableKeyEvents()
|
||||
|
||||
/**
|
||||
* When enabled, LayoutAnimations API will animate state changes on Android.
|
||||
*/
|
||||
@@ -306,6 +312,12 @@ public object ReactNativeFeatureFlags {
|
||||
@JvmStatic
|
||||
public fun enableViewRecyclingForView(): Boolean = accessor.enableViewRecyclingForView()
|
||||
|
||||
/**
|
||||
* Set clipping to drawingRect of ScrollView.
|
||||
*/
|
||||
@JvmStatic
|
||||
public fun enableVirtualViewClippingWithoutScrollViewClipping(): Boolean = accessor.enableVirtualViewClippingWithoutScrollViewClipping()
|
||||
|
||||
/**
|
||||
* Enables the experimental version of `VirtualViewContainerState`.
|
||||
*/
|
||||
@@ -366,6 +378,12 @@ public object ReactNativeFeatureFlags {
|
||||
@JvmStatic
|
||||
public fun overrideBySynchronousMountPropsAtMountingAndroid(): Boolean = accessor.overrideBySynchronousMountPropsAtMountingAndroid()
|
||||
|
||||
/**
|
||||
* Enable reporting Performance Issues (`detail.rnPerfIssue`). Displayed in the V2 Performance Monitor and the "Performance Issues" sub-panel in DevTools.
|
||||
*/
|
||||
@JvmStatic
|
||||
public fun perfIssuesEnabled(): Boolean = accessor.perfIssuesEnabled()
|
||||
|
||||
/**
|
||||
* Enable the V2 in-app Performance Monitor. This flag is global and should not be changed across React Host lifetimes.
|
||||
*/
|
||||
|
||||
+31
-1
@@ -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<<ba1a322a9c7069cf63fd759090f9025d>>
|
||||
* @generated SignedSource<<447ccc7271b71b0208a2297b7eba5995>>
|
||||
*/
|
||||
|
||||
/**
|
||||
@@ -50,6 +50,7 @@ internal class ReactNativeFeatureFlagsCxxAccessor : ReactNativeFeatureFlagsAcces
|
||||
private var enableImmediateUpdateModeForContentOffsetChangesCache: Boolean? = null
|
||||
private var enableImperativeFocusCache: Boolean? = null
|
||||
private var enableInteropViewManagerClassLookUpOptimizationIOSCache: Boolean? = null
|
||||
private var enableKeyEventsCache: Boolean? = null
|
||||
private var enableLayoutAnimationsOnAndroidCache: Boolean? = null
|
||||
private var enableLayoutAnimationsOnIOSCache: Boolean? = null
|
||||
private var enableMainQueueCoordinatorOnIOSCache: Boolean? = null
|
||||
@@ -66,6 +67,7 @@ internal class ReactNativeFeatureFlagsCxxAccessor : ReactNativeFeatureFlagsAcces
|
||||
private var enableViewRecyclingForScrollViewCache: Boolean? = null
|
||||
private var enableViewRecyclingForTextCache: Boolean? = null
|
||||
private var enableViewRecyclingForViewCache: Boolean? = null
|
||||
private var enableVirtualViewClippingWithoutScrollViewClippingCache: Boolean? = null
|
||||
private var enableVirtualViewContainerStateExperimentalCache: Boolean? = null
|
||||
private var enableVirtualViewDebugFeaturesCache: Boolean? = null
|
||||
private var enableVirtualViewRenderStateCache: Boolean? = null
|
||||
@@ -76,6 +78,7 @@ internal class ReactNativeFeatureFlagsCxxAccessor : ReactNativeFeatureFlagsAcces
|
||||
private var fuseboxNetworkInspectionEnabledCache: Boolean? = null
|
||||
private var hideOffscreenVirtualViewsOnIOSCache: Boolean? = null
|
||||
private var overrideBySynchronousMountPropsAtMountingAndroidCache: Boolean? = null
|
||||
private var perfIssuesEnabledCache: Boolean? = null
|
||||
private var perfMonitorV2EnabledCache: Boolean? = null
|
||||
private var preparedTextCacheSizeCache: Double? = null
|
||||
private var preventShadowTreeCommitExhaustionCache: Boolean? = null
|
||||
@@ -371,6 +374,15 @@ internal class ReactNativeFeatureFlagsCxxAccessor : ReactNativeFeatureFlagsAcces
|
||||
return cached
|
||||
}
|
||||
|
||||
override fun enableKeyEvents(): Boolean {
|
||||
var cached = enableKeyEventsCache
|
||||
if (cached == null) {
|
||||
cached = ReactNativeFeatureFlagsCxxInterop.enableKeyEvents()
|
||||
enableKeyEventsCache = cached
|
||||
}
|
||||
return cached
|
||||
}
|
||||
|
||||
override fun enableLayoutAnimationsOnAndroid(): Boolean {
|
||||
var cached = enableLayoutAnimationsOnAndroidCache
|
||||
if (cached == null) {
|
||||
@@ -515,6 +527,15 @@ internal class ReactNativeFeatureFlagsCxxAccessor : ReactNativeFeatureFlagsAcces
|
||||
return cached
|
||||
}
|
||||
|
||||
override fun enableVirtualViewClippingWithoutScrollViewClipping(): Boolean {
|
||||
var cached = enableVirtualViewClippingWithoutScrollViewClippingCache
|
||||
if (cached == null) {
|
||||
cached = ReactNativeFeatureFlagsCxxInterop.enableVirtualViewClippingWithoutScrollViewClipping()
|
||||
enableVirtualViewClippingWithoutScrollViewClippingCache = cached
|
||||
}
|
||||
return cached
|
||||
}
|
||||
|
||||
override fun enableVirtualViewContainerStateExperimental(): Boolean {
|
||||
var cached = enableVirtualViewContainerStateExperimentalCache
|
||||
if (cached == null) {
|
||||
@@ -605,6 +626,15 @@ internal class ReactNativeFeatureFlagsCxxAccessor : ReactNativeFeatureFlagsAcces
|
||||
return cached
|
||||
}
|
||||
|
||||
override fun perfIssuesEnabled(): Boolean {
|
||||
var cached = perfIssuesEnabledCache
|
||||
if (cached == null) {
|
||||
cached = ReactNativeFeatureFlagsCxxInterop.perfIssuesEnabled()
|
||||
perfIssuesEnabledCache = cached
|
||||
}
|
||||
return cached
|
||||
}
|
||||
|
||||
override fun perfMonitorV2Enabled(): Boolean {
|
||||
var cached = perfMonitorV2EnabledCache
|
||||
if (cached == null) {
|
||||
|
||||
+7
-1
@@ -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<<412a865e975214a0d794985e48fbbe4b>>
|
||||
* @generated SignedSource<<d6403b67e269ad80ef3e2389ac923c8a>>
|
||||
*/
|
||||
|
||||
/**
|
||||
@@ -88,6 +88,8 @@ public object ReactNativeFeatureFlagsCxxInterop {
|
||||
|
||||
@DoNotStrip @JvmStatic public external fun enableInteropViewManagerClassLookUpOptimizationIOS(): Boolean
|
||||
|
||||
@DoNotStrip @JvmStatic public external fun enableKeyEvents(): Boolean
|
||||
|
||||
@DoNotStrip @JvmStatic public external fun enableLayoutAnimationsOnAndroid(): Boolean
|
||||
|
||||
@DoNotStrip @JvmStatic public external fun enableLayoutAnimationsOnIOS(): Boolean
|
||||
@@ -120,6 +122,8 @@ public object ReactNativeFeatureFlagsCxxInterop {
|
||||
|
||||
@DoNotStrip @JvmStatic public external fun enableViewRecyclingForView(): Boolean
|
||||
|
||||
@DoNotStrip @JvmStatic public external fun enableVirtualViewClippingWithoutScrollViewClipping(): Boolean
|
||||
|
||||
@DoNotStrip @JvmStatic public external fun enableVirtualViewContainerStateExperimental(): Boolean
|
||||
|
||||
@DoNotStrip @JvmStatic public external fun enableVirtualViewDebugFeatures(): Boolean
|
||||
@@ -140,6 +144,8 @@ public object ReactNativeFeatureFlagsCxxInterop {
|
||||
|
||||
@DoNotStrip @JvmStatic public external fun overrideBySynchronousMountPropsAtMountingAndroid(): Boolean
|
||||
|
||||
@DoNotStrip @JvmStatic public external fun perfIssuesEnabled(): Boolean
|
||||
|
||||
@DoNotStrip @JvmStatic public external fun perfMonitorV2Enabled(): Boolean
|
||||
|
||||
@DoNotStrip @JvmStatic public external fun preparedTextCacheSize(): Double
|
||||
|
||||
+9
-3
@@ -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<<7987eba84c39c6e8cb6494092a94790e>>
|
||||
* @generated SignedSource<<ab48ba86a7cf3cd35ec530a216aea774>>
|
||||
*/
|
||||
|
||||
/**
|
||||
@@ -83,6 +83,8 @@ public open class ReactNativeFeatureFlagsDefaults : ReactNativeFeatureFlagsProvi
|
||||
|
||||
override fun enableInteropViewManagerClassLookUpOptimizationIOS(): Boolean = false
|
||||
|
||||
override fun enableKeyEvents(): Boolean = false
|
||||
|
||||
override fun enableLayoutAnimationsOnAndroid(): Boolean = false
|
||||
|
||||
override fun enableLayoutAnimationsOnIOS(): Boolean = true
|
||||
@@ -115,6 +117,8 @@ public open class ReactNativeFeatureFlagsDefaults : ReactNativeFeatureFlagsProvi
|
||||
|
||||
override fun enableViewRecyclingForView(): Boolean = true
|
||||
|
||||
override fun enableVirtualViewClippingWithoutScrollViewClipping(): Boolean = true
|
||||
|
||||
override fun enableVirtualViewContainerStateExperimental(): Boolean = false
|
||||
|
||||
override fun enableVirtualViewDebugFeatures(): Boolean = false
|
||||
@@ -123,7 +127,7 @@ public open class ReactNativeFeatureFlagsDefaults : ReactNativeFeatureFlagsProvi
|
||||
|
||||
override fun enableVirtualViewWindowFocusDetection(): Boolean = false
|
||||
|
||||
override fun enableWebPerformanceAPIsByDefault(): Boolean = false
|
||||
override fun enableWebPerformanceAPIsByDefault(): Boolean = true
|
||||
|
||||
override fun fixMappingOfEventPrioritiesBetweenFabricAndReact(): Boolean = false
|
||||
|
||||
@@ -135,6 +139,8 @@ public open class ReactNativeFeatureFlagsDefaults : ReactNativeFeatureFlagsProvi
|
||||
|
||||
override fun overrideBySynchronousMountPropsAtMountingAndroid(): Boolean = false
|
||||
|
||||
override fun perfIssuesEnabled(): Boolean = false
|
||||
|
||||
override fun perfMonitorV2Enabled(): Boolean = false
|
||||
|
||||
override fun preparedTextCacheSize(): Double = 200.0
|
||||
@@ -147,7 +153,7 @@ public open class ReactNativeFeatureFlagsDefaults : ReactNativeFeatureFlagsProvi
|
||||
|
||||
override fun skipActivityIdentityAssertionOnHostPause(): Boolean = false
|
||||
|
||||
override fun sweepActiveTouchOnChildNativeGesturesAndroid(): Boolean = false
|
||||
override fun sweepActiveTouchOnChildNativeGesturesAndroid(): Boolean = true
|
||||
|
||||
override fun traceTurboModulePromiseRejectionsOnAndroid(): Boolean = false
|
||||
|
||||
|
||||
+34
-1
@@ -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<<7f43cde1ba2bef2300c077f35b168d31>>
|
||||
* @generated SignedSource<<6f6b5abe79764b88cf3ed62fe0230786>>
|
||||
*/
|
||||
|
||||
/**
|
||||
@@ -54,6 +54,7 @@ internal class ReactNativeFeatureFlagsLocalAccessor : ReactNativeFeatureFlagsAcc
|
||||
private var enableImmediateUpdateModeForContentOffsetChangesCache: Boolean? = null
|
||||
private var enableImperativeFocusCache: Boolean? = null
|
||||
private var enableInteropViewManagerClassLookUpOptimizationIOSCache: Boolean? = null
|
||||
private var enableKeyEventsCache: Boolean? = null
|
||||
private var enableLayoutAnimationsOnAndroidCache: Boolean? = null
|
||||
private var enableLayoutAnimationsOnIOSCache: Boolean? = null
|
||||
private var enableMainQueueCoordinatorOnIOSCache: Boolean? = null
|
||||
@@ -70,6 +71,7 @@ internal class ReactNativeFeatureFlagsLocalAccessor : ReactNativeFeatureFlagsAcc
|
||||
private var enableViewRecyclingForScrollViewCache: Boolean? = null
|
||||
private var enableViewRecyclingForTextCache: Boolean? = null
|
||||
private var enableViewRecyclingForViewCache: Boolean? = null
|
||||
private var enableVirtualViewClippingWithoutScrollViewClippingCache: Boolean? = null
|
||||
private var enableVirtualViewContainerStateExperimentalCache: Boolean? = null
|
||||
private var enableVirtualViewDebugFeaturesCache: Boolean? = null
|
||||
private var enableVirtualViewRenderStateCache: Boolean? = null
|
||||
@@ -80,6 +82,7 @@ internal class ReactNativeFeatureFlagsLocalAccessor : ReactNativeFeatureFlagsAcc
|
||||
private var fuseboxNetworkInspectionEnabledCache: Boolean? = null
|
||||
private var hideOffscreenVirtualViewsOnIOSCache: Boolean? = null
|
||||
private var overrideBySynchronousMountPropsAtMountingAndroidCache: Boolean? = null
|
||||
private var perfIssuesEnabledCache: Boolean? = null
|
||||
private var perfMonitorV2EnabledCache: Boolean? = null
|
||||
private var preparedTextCacheSizeCache: Double? = null
|
||||
private var preventShadowTreeCommitExhaustionCache: Boolean? = null
|
||||
@@ -405,6 +408,16 @@ internal class ReactNativeFeatureFlagsLocalAccessor : ReactNativeFeatureFlagsAcc
|
||||
return cached
|
||||
}
|
||||
|
||||
override fun enableKeyEvents(): Boolean {
|
||||
var cached = enableKeyEventsCache
|
||||
if (cached == null) {
|
||||
cached = currentProvider.enableKeyEvents()
|
||||
accessedFeatureFlags.add("enableKeyEvents")
|
||||
enableKeyEventsCache = cached
|
||||
}
|
||||
return cached
|
||||
}
|
||||
|
||||
override fun enableLayoutAnimationsOnAndroid(): Boolean {
|
||||
var cached = enableLayoutAnimationsOnAndroidCache
|
||||
if (cached == null) {
|
||||
@@ -565,6 +578,16 @@ internal class ReactNativeFeatureFlagsLocalAccessor : ReactNativeFeatureFlagsAcc
|
||||
return cached
|
||||
}
|
||||
|
||||
override fun enableVirtualViewClippingWithoutScrollViewClipping(): Boolean {
|
||||
var cached = enableVirtualViewClippingWithoutScrollViewClippingCache
|
||||
if (cached == null) {
|
||||
cached = currentProvider.enableVirtualViewClippingWithoutScrollViewClipping()
|
||||
accessedFeatureFlags.add("enableVirtualViewClippingWithoutScrollViewClipping")
|
||||
enableVirtualViewClippingWithoutScrollViewClippingCache = cached
|
||||
}
|
||||
return cached
|
||||
}
|
||||
|
||||
override fun enableVirtualViewContainerStateExperimental(): Boolean {
|
||||
var cached = enableVirtualViewContainerStateExperimentalCache
|
||||
if (cached == null) {
|
||||
@@ -665,6 +688,16 @@ internal class ReactNativeFeatureFlagsLocalAccessor : ReactNativeFeatureFlagsAcc
|
||||
return cached
|
||||
}
|
||||
|
||||
override fun perfIssuesEnabled(): Boolean {
|
||||
var cached = perfIssuesEnabledCache
|
||||
if (cached == null) {
|
||||
cached = currentProvider.perfIssuesEnabled()
|
||||
accessedFeatureFlags.add("perfIssuesEnabled")
|
||||
perfIssuesEnabledCache = cached
|
||||
}
|
||||
return cached
|
||||
}
|
||||
|
||||
override fun perfMonitorV2Enabled(): Boolean {
|
||||
var cached = perfMonitorV2EnabledCache
|
||||
if (cached == null) {
|
||||
|
||||
+1
-3
@@ -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<<4464982256b8ce543d9235fccbf67054>>
|
||||
* @generated SignedSource<<f82b5905d822f8009c054a9443f86e39>>
|
||||
*/
|
||||
|
||||
/**
|
||||
@@ -27,8 +27,6 @@ public open class ReactNativeFeatureFlagsOverrides_RNOSS_Canary_Android : ReactN
|
||||
|
||||
override fun enableFabricRenderer(): Boolean = true
|
||||
|
||||
override fun enableWebPerformanceAPIsByDefault(): Boolean = true
|
||||
|
||||
override fun useNativeViewConfigsInBridgelessMode(): Boolean = true
|
||||
|
||||
override fun useTurboModuleInterop(): Boolean = true
|
||||
|
||||
+7
-1
@@ -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<<692dcdb2af3c6af981e8f48686ca105e>>
|
||||
* @generated SignedSource<<6b61490a8d6b1df1d6264016455382f8>>
|
||||
*/
|
||||
|
||||
/**
|
||||
@@ -83,6 +83,8 @@ public interface ReactNativeFeatureFlagsProvider {
|
||||
|
||||
@DoNotStrip public fun enableInteropViewManagerClassLookUpOptimizationIOS(): Boolean
|
||||
|
||||
@DoNotStrip public fun enableKeyEvents(): Boolean
|
||||
|
||||
@DoNotStrip public fun enableLayoutAnimationsOnAndroid(): Boolean
|
||||
|
||||
@DoNotStrip public fun enableLayoutAnimationsOnIOS(): Boolean
|
||||
@@ -115,6 +117,8 @@ public interface ReactNativeFeatureFlagsProvider {
|
||||
|
||||
@DoNotStrip public fun enableViewRecyclingForView(): Boolean
|
||||
|
||||
@DoNotStrip public fun enableVirtualViewClippingWithoutScrollViewClipping(): Boolean
|
||||
|
||||
@DoNotStrip public fun enableVirtualViewContainerStateExperimental(): Boolean
|
||||
|
||||
@DoNotStrip public fun enableVirtualViewDebugFeatures(): Boolean
|
||||
@@ -135,6 +139,8 @@ public interface ReactNativeFeatureFlagsProvider {
|
||||
|
||||
@DoNotStrip public fun overrideBySynchronousMountPropsAtMountingAndroid(): Boolean
|
||||
|
||||
@DoNotStrip public fun perfIssuesEnabled(): Boolean
|
||||
|
||||
@DoNotStrip public fun perfMonitorV2Enabled(): Boolean
|
||||
|
||||
@DoNotStrip public fun preparedTextCacheSize(): Double
|
||||
|
||||
+109
@@ -0,0 +1,109 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package com.facebook.react.internal.tracing
|
||||
|
||||
import com.facebook.proguard.annotations.DoNotStrip
|
||||
import com.facebook.react.bridge.ReadableNativeMap
|
||||
import com.facebook.soloader.SoLoader
|
||||
|
||||
/**
|
||||
* JNI interface to access PerformanceTracer methods from React Native Inspector Modern.
|
||||
*
|
||||
* This provides access to reportMark and reportMeasure methods which are used for performance
|
||||
* tracing in the React Native DevTools.
|
||||
*/
|
||||
@DoNotStrip
|
||||
public object PerformanceTracer {
|
||||
init {
|
||||
SoLoader.loadLibrary("react_performancetracerjni")
|
||||
}
|
||||
|
||||
/** Callback interface for tracing state changes. */
|
||||
@DoNotStrip
|
||||
public interface TracingStateCallback {
|
||||
/**
|
||||
* Called when tracing state changes.
|
||||
*
|
||||
* @param isTracing true if tracing has started, false if tracing has stopped
|
||||
*/
|
||||
@DoNotStrip public fun onTracingStateChanged(isTracing: Boolean)
|
||||
}
|
||||
|
||||
/**
|
||||
* Report a Performance.mark() event - a labelled timestamp.
|
||||
*
|
||||
* @param name The name/label of the mark
|
||||
* @param timestampNanos The timestamp in nanoseconds (monotonic time)
|
||||
* @param detail Optional map with additional detail (pass null if not needed)
|
||||
*/
|
||||
@DoNotStrip
|
||||
@JvmStatic
|
||||
public external fun reportMark(name: String, timestampNanos: Long, detail: ReadableNativeMap?)
|
||||
|
||||
/**
|
||||
* Report a Performance.measure() event - a labelled duration.
|
||||
*
|
||||
* @param name The name/label of the measure
|
||||
* @param startTimestampNanos The start timestamp in nanoseconds (monotonic time)
|
||||
* @param durationNanos The duration in nanoseconds
|
||||
* @param detail Optional map with additional detail (pass null if not needed)
|
||||
*/
|
||||
@DoNotStrip
|
||||
@JvmStatic
|
||||
public external fun reportMeasure(
|
||||
name: String,
|
||||
startTimestampNanos: Long,
|
||||
durationNanos: Long,
|
||||
detail: ReadableNativeMap?,
|
||||
)
|
||||
|
||||
/**
|
||||
* Report a TimeStamp Trace Event - a labelled entry on Performance timeline.
|
||||
*
|
||||
* @param name The name/label of the timestamp
|
||||
* @param startTimeNanos Start timestamp in nanoseconds (monotonic time)
|
||||
* @param endTimeNanos End timestamp in nanoseconds (monotonic time)
|
||||
* @param trackName Optional track name for organizing the timestamp
|
||||
* @param trackGroup Optional track group for organizing the timestamp
|
||||
* @param color Optional color name (e.g., "primary", "secondary", "error", "warning")
|
||||
*/
|
||||
@DoNotStrip
|
||||
@JvmStatic
|
||||
public external fun reportTimeStamp(
|
||||
name: String,
|
||||
startTimeNanos: Long,
|
||||
endTimeNanos: Long,
|
||||
trackName: String?,
|
||||
trackGroup: String?,
|
||||
color: String?,
|
||||
)
|
||||
|
||||
/**
|
||||
* Check if the tracer is currently tracing.
|
||||
*
|
||||
* @return true if tracing is active, false otherwise
|
||||
*/
|
||||
@DoNotStrip @JvmStatic public external fun isTracing(): Boolean
|
||||
|
||||
/**
|
||||
* Subscribe to tracing state changes (start/stop events).
|
||||
*
|
||||
* @param callback The callback to invoke when tracing starts or stops
|
||||
* @return A subscription ID that can be used to unsubscribe
|
||||
*/
|
||||
@DoNotStrip
|
||||
@JvmStatic
|
||||
public external fun subscribeToTracingStateChanges(callback: TracingStateCallback): Int
|
||||
|
||||
/**
|
||||
* Unsubscribe from tracing state changes.
|
||||
*
|
||||
* @param subscriptionId The subscription ID returned from subscribeToTracingStateChanges
|
||||
*/
|
||||
@DoNotStrip @JvmStatic public external fun unsubscribeFromTracingStateChanges(subscriptionId: Int)
|
||||
}
|
||||
+6
@@ -74,6 +74,12 @@ internal class ReactHostInspectorTarget(reactHostImpl: ReactHostImpl) :
|
||||
}
|
||||
}
|
||||
|
||||
fun handleNativePerfIssueAdded(
|
||||
name: String,
|
||||
) {
|
||||
perfMonitorListeners.forEach { listener -> listener.onPerfIssueAdded(name) }
|
||||
}
|
||||
|
||||
override fun close() {
|
||||
mHybridData.resetNative()
|
||||
}
|
||||
|
||||
+160
-2
@@ -45,12 +45,22 @@ import com.facebook.react.uimanager.style.LogicalEdge
|
||||
import com.facebook.react.uimanager.style.OutlineStyle
|
||||
|
||||
/**
|
||||
* BackgroundStyleApplicator is responsible for applying backgrounds, borders, and related effects,
|
||||
* to an Android view
|
||||
* Utility object responsible for applying backgrounds, borders, and related visual effects to
|
||||
* Android views.
|
||||
*
|
||||
* This object provides methods to manage background colors, images, borders, outlines, and box
|
||||
* shadows for React Native views. It handles the complex layering and composition of these visual
|
||||
* properties by managing [CompositeBackgroundDrawable] instances.
|
||||
*/
|
||||
@OptIn(UnstableReactNativeAPI::class)
|
||||
public object BackgroundStyleApplicator {
|
||||
|
||||
/**
|
||||
* Sets the background color of the view.
|
||||
*
|
||||
* @param view The view to apply the background color to
|
||||
* @param color The color to set, or null to remove the background color
|
||||
*/
|
||||
@JvmStatic
|
||||
public fun setBackgroundColor(view: View, @ColorInt color: Int?): Unit {
|
||||
// No color to set, and no color already set
|
||||
@@ -64,6 +74,12 @@ public object BackgroundStyleApplicator {
|
||||
ensureBackgroundDrawable(view).backgroundColor = color ?: Color.TRANSPARENT
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the background image layers for the view.
|
||||
*
|
||||
* @param view The view to apply the background images to
|
||||
* @param backgroundImageLayers The list of background image layers to apply, or null to remove
|
||||
*/
|
||||
@JvmStatic
|
||||
public fun setBackgroundImage(
|
||||
view: View,
|
||||
@@ -90,12 +106,25 @@ public object BackgroundStyleApplicator {
|
||||
ensureBackgroundImageDrawable(view).backgroundRepeat = backgroundRepeats
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the background color of the view.
|
||||
*
|
||||
* @param view The view to get the background color from
|
||||
* @return The background color, or null if no background color is set
|
||||
*/
|
||||
@JvmStatic
|
||||
@ColorInt
|
||||
public fun getBackgroundColor(view: View): Int? {
|
||||
return getBackground(view)?.backgroundColor
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the border width for a specific edge of the view.
|
||||
*
|
||||
* @param view The view to apply the border width to
|
||||
* @param edge The logical edge (start, end, top, bottom, etc.) to set the width for
|
||||
* @param width The border width in DIPs, or null to remove
|
||||
*/
|
||||
@JvmStatic
|
||||
public fun setBorderWidth(view: View, edge: LogicalEdge, width: Float?): Unit {
|
||||
val composite = ensureCompositeBackgroundDrawable(view)
|
||||
@@ -121,6 +150,13 @@ public object BackgroundStyleApplicator {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the border width for a specific edge of the view.
|
||||
*
|
||||
* @param view The view to get the border width from
|
||||
* @param edge The logical edge to get the width for
|
||||
* @return The border width in DIPs, or null if not set
|
||||
*/
|
||||
@JvmStatic
|
||||
public fun getBorderWidth(view: View, edge: LogicalEdge): Float? {
|
||||
val width = getBorder(view)?.borderWidth?.getRaw(edge.toSpacingType())
|
||||
@@ -131,17 +167,38 @@ public object BackgroundStyleApplicator {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the border color for a specific edge of the view.
|
||||
*
|
||||
* @param view The view to apply the border color to
|
||||
* @param edge The logical edge to set the color for
|
||||
* @param color The border color, or null to remove
|
||||
*/
|
||||
@JvmStatic
|
||||
public fun setBorderColor(view: View, edge: LogicalEdge, @ColorInt color: Int?): Unit {
|
||||
ensureBorderDrawable(view).setBorderColor(edge, color)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the border color for a specific edge of the view.
|
||||
*
|
||||
* @param view The view to get the border color from
|
||||
* @param edge The logical edge to get the color for
|
||||
* @return The border color, or null if not set
|
||||
*/
|
||||
@JvmStatic
|
||||
@ColorInt
|
||||
public fun getBorderColor(view: View, edge: LogicalEdge): Int? {
|
||||
return getBorder(view)?.getBorderColor(edge)
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the border radius for a specific corner of the view.
|
||||
*
|
||||
* @param view The view to apply the border radius to
|
||||
* @param corner The corner property to set the radius for
|
||||
* @param radius The border radius value (length or percentage), or null to remove
|
||||
*/
|
||||
@JvmStatic
|
||||
public fun setBorderRadius(
|
||||
view: View,
|
||||
@@ -183,22 +240,47 @@ public object BackgroundStyleApplicator {
|
||||
compositeBackgroundDrawable.invalidateSelf()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the border radius for a specific corner of the view.
|
||||
*
|
||||
* @param view The view to get the border radius from
|
||||
* @param corner The corner property to get the radius for
|
||||
* @return The border radius value, or null if not set
|
||||
*/
|
||||
@JvmStatic
|
||||
public fun getBorderRadius(view: View, corner: BorderRadiusProp): LengthPercentage? {
|
||||
|
||||
return getCompositeBackgroundDrawable(view)?.borderRadius?.get(corner)
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the border style for the view.
|
||||
*
|
||||
* @param view The view to apply the border style to
|
||||
* @param borderStyle The border style (solid, dashed, dotted), or null to remove
|
||||
*/
|
||||
@JvmStatic
|
||||
public fun setBorderStyle(view: View, borderStyle: BorderStyle?) {
|
||||
ensureBorderDrawable(view).borderStyle = borderStyle
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the border style of the view.
|
||||
*
|
||||
* @param view The view to get the border style from
|
||||
* @return The border style, or null if not set
|
||||
*/
|
||||
@JvmStatic
|
||||
public fun getBorderStyle(view: View): BorderStyle? {
|
||||
return getBorder(view)?.borderStyle
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the outline color for the view (Fabric only).
|
||||
*
|
||||
* @param view The view to apply the outline color to
|
||||
* @param outlineColor The outline color, or null to remove
|
||||
*/
|
||||
@JvmStatic
|
||||
public fun setOutlineColor(view: View, @ColorInt outlineColor: Int?) {
|
||||
if (ViewUtil.getUIManagerType(view) != UIManagerType.FABRIC) {
|
||||
@@ -211,8 +293,20 @@ public object BackgroundStyleApplicator {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the outline color of the view.
|
||||
*
|
||||
* @param view The view to get the outline color from
|
||||
* @return The outline color, or null if not set
|
||||
*/
|
||||
@JvmStatic public fun getOutlineColor(view: View): Int? = getOutlineDrawable(view)?.outlineColor
|
||||
|
||||
/**
|
||||
* Sets the outline offset for the view (Fabric only).
|
||||
*
|
||||
* @param view The view to apply the outline offset to
|
||||
* @param outlineOffset The outline offset in DIPs
|
||||
*/
|
||||
@JvmStatic
|
||||
public fun setOutlineOffset(view: View, outlineOffset: Float): Unit {
|
||||
if (ViewUtil.getUIManagerType(view) != UIManagerType.FABRIC) {
|
||||
@@ -223,8 +317,20 @@ public object BackgroundStyleApplicator {
|
||||
outline.outlineOffset = outlineOffset.dpToPx()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the outline offset of the view.
|
||||
*
|
||||
* @param view The view to get the outline offset from
|
||||
* @return The outline offset in pixels, or null if not set
|
||||
*/
|
||||
public fun getOutlineOffset(view: View): Float? = getOutlineDrawable(view)?.outlineOffset
|
||||
|
||||
/**
|
||||
* Sets the outline style for the view (Fabric only).
|
||||
*
|
||||
* @param view The view to apply the outline style to
|
||||
* @param outlineStyle The outline style (solid, dashed, dotted), or null to remove
|
||||
*/
|
||||
@JvmStatic
|
||||
public fun setOutlineStyle(view: View, outlineStyle: OutlineStyle?): Unit {
|
||||
if (ViewUtil.getUIManagerType(view) != UIManagerType.FABRIC) {
|
||||
@@ -237,8 +343,20 @@ public object BackgroundStyleApplicator {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the outline style of the view.
|
||||
*
|
||||
* @param view The view to get the outline style from
|
||||
* @return The outline style, or null if not set
|
||||
*/
|
||||
public fun getOutlineStyle(view: View): OutlineStyle? = getOutlineDrawable(view)?.outlineStyle
|
||||
|
||||
/**
|
||||
* Sets the outline width for the view (Fabric only).
|
||||
*
|
||||
* @param view The view to apply the outline width to
|
||||
* @param width The outline width in DIPs
|
||||
*/
|
||||
@JvmStatic
|
||||
public fun setOutlineWidth(view: View, width: Float) {
|
||||
if (ViewUtil.getUIManagerType(view) != UIManagerType.FABRIC) {
|
||||
@@ -249,8 +367,20 @@ public object BackgroundStyleApplicator {
|
||||
outline.outlineWidth = width.dpToPx()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the outline width of the view.
|
||||
*
|
||||
* @param view The view to get the outline width from
|
||||
* @return The outline width in pixels, or null if not set
|
||||
*/
|
||||
public fun getOutlineWidth(view: View): Float? = getOutlineDrawable(view)?.outlineOffset
|
||||
|
||||
/**
|
||||
* Sets box shadows for the view (Fabric only).
|
||||
*
|
||||
* @param view The view to apply box shadows to
|
||||
* @param shadows The list of box shadow styles to apply
|
||||
*/
|
||||
@JvmStatic
|
||||
public fun setBoxShadow(view: View, shadows: List<BoxShadow>) {
|
||||
if (ViewUtil.getUIManagerType(view) != UIManagerType.FABRIC) {
|
||||
@@ -309,6 +439,12 @@ public object BackgroundStyleApplicator {
|
||||
.withNewShadows(outerShadows = outerShadows, innerShadows = innerShadows)
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets box shadows for the view from a ReadableArray (Fabric only).
|
||||
*
|
||||
* @param view The view to apply box shadows to
|
||||
* @param shadows The array of box shadow definitions, or null to remove all shadows
|
||||
*/
|
||||
@JvmStatic
|
||||
public fun setBoxShadow(view: View, shadows: ReadableArray?) {
|
||||
if (shadows == null) {
|
||||
@@ -323,11 +459,26 @@ public object BackgroundStyleApplicator {
|
||||
BackgroundStyleApplicator.setBoxShadow(view, shadowStyles)
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a feedback underlay drawable for the view.
|
||||
*
|
||||
* @param view The view to apply the feedback underlay to
|
||||
* @param drawable The drawable to use as feedback underlay, or null to remove
|
||||
*/
|
||||
@JvmStatic
|
||||
public fun setFeedbackUnderlay(view: View, drawable: Drawable?) {
|
||||
ensureCompositeBackgroundDrawable(view).withNewFeedbackUnderlay(drawable)
|
||||
}
|
||||
|
||||
/**
|
||||
* Clips the canvas to the padding box of the view.
|
||||
*
|
||||
* The padding box is the area within the borders of the view, accounting for border radius if
|
||||
* present.
|
||||
*
|
||||
* @param view The view whose padding box defines the clipping region
|
||||
* @param canvas The canvas to clip
|
||||
*/
|
||||
@JvmStatic
|
||||
public fun clipToPaddingBox(view: View, canvas: Canvas) {
|
||||
val drawingRect = Rect()
|
||||
@@ -366,6 +517,13 @@ public object BackgroundStyleApplicator {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the background styling of the view to its original state.
|
||||
*
|
||||
* This removes any CompositeBackgroundDrawable and restores the original background.
|
||||
*
|
||||
* @param view The view to reset
|
||||
*/
|
||||
@JvmStatic
|
||||
public fun reset(view: View) {
|
||||
if (view.background is CompositeBackgroundDrawable) {
|
||||
|
||||
+14
-1
@@ -14,10 +14,23 @@ import android.view.ViewGroup
|
||||
import androidx.core.view.children
|
||||
import com.facebook.react.R
|
||||
|
||||
/**
|
||||
* Helper object for parsing and handling CSS mix-blend-mode properties on Android Q+ (API 29+).
|
||||
*
|
||||
* This object provides utilities to convert CSS mix-blend-mode string values into Android's
|
||||
* [BlendMode] enumeration and to determine when views need isolated layers for proper blending.
|
||||
*/
|
||||
@TargetApi(29)
|
||||
internal object BlendModeHelper {
|
||||
|
||||
/** @see <a href="https://www.w3.org/TR/compositing-1/#mix-blend-mode">mix-blend-mode</a> */
|
||||
/**
|
||||
* Parses a CSS mix-blend-mode string value into an Android BlendMode.
|
||||
*
|
||||
* @param mixBlendMode The CSS mix-blend-mode value (e.g., "multiply", "screen", "overlay")
|
||||
* @return The corresponding [BlendMode], or null if "normal" or on unsupported Android versions
|
||||
* @throws IllegalArgumentException if the mix-blend-mode name is invalid
|
||||
* @see <a href="https://www.w3.org/TR/compositing-1/#mix-blend-mode">mix-blend-mode</a>
|
||||
*/
|
||||
@JvmStatic
|
||||
fun parseMixBlendMode(mixBlendMode: String?): BlendMode? {
|
||||
if (mixBlendMode == null || Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {
|
||||
|
||||
+11
-1
@@ -9,8 +9,18 @@ package com.facebook.react.uimanager
|
||||
|
||||
import com.facebook.proguard.annotations.DoNotStripAny
|
||||
|
||||
/**
|
||||
* Interface for resolving component names registered in React Native.
|
||||
*
|
||||
* This interface provides access to all registered component names in the React Native runtime,
|
||||
* which is useful for debugging and inspection purposes.
|
||||
*/
|
||||
@DoNotStripAny
|
||||
internal interface ComponentNameResolver {
|
||||
/* returns a list of all the component names that are registered in React Native. */
|
||||
/**
|
||||
* Gets the list of all component names registered in React Native.
|
||||
*
|
||||
* @return An array of all registered component names
|
||||
*/
|
||||
val componentNames: Array<String>
|
||||
}
|
||||
|
||||
+12
@@ -12,11 +12,23 @@ import com.facebook.react.bridge.RuntimeExecutor
|
||||
import com.facebook.soloader.SoLoader
|
||||
import kotlin.jvm.JvmStatic
|
||||
|
||||
/**
|
||||
* JNI binding for installing a ComponentNameResolver into the JavaScript runtime.
|
||||
*
|
||||
* This object provides a native binding to install a [ComponentNameResolver] into the React Native
|
||||
* JavaScript runtime, making component name information available to the native side.
|
||||
*/
|
||||
@DoNotStripAny
|
||||
internal object ComponentNameResolverBinding {
|
||||
init {
|
||||
SoLoader.loadLibrary("uimanagerjni")
|
||||
}
|
||||
|
||||
/**
|
||||
* Installs a ComponentNameResolver into the JavaScript runtime.
|
||||
*
|
||||
* @param runtimeExecutor The runtime executor for the JavaScript runtime
|
||||
* @param componentNameResolver The component name resolver to install
|
||||
*/
|
||||
@JvmStatic external fun install(runtimeExecutor: RuntimeExecutor, componentNameResolver: Any)
|
||||
}
|
||||
|
||||
+16
@@ -21,9 +21,25 @@ import com.facebook.react.uimanager.PixelUtil.dpToPx
|
||||
import kotlin.math.cos
|
||||
import kotlin.math.sin
|
||||
|
||||
/**
|
||||
* Helper object for parsing and applying CSS filter effects on Android S+ (API 31+).
|
||||
*
|
||||
* This object provides utilities to convert CSS filter arrays into Android [RenderEffect] chains
|
||||
* and [ColorMatrixColorFilter] objects. Supports filters like blur, brightness, contrast,
|
||||
* grayscale, sepia, saturate, hue-rotate, invert, opacity, and drop-shadow.
|
||||
*
|
||||
* @see <a href="https://www.w3.org/TR/filter-effects-1/">CSS Filter Effects Module Level 1</a>
|
||||
*/
|
||||
@TargetApi(31)
|
||||
internal object FilterHelper {
|
||||
|
||||
/**
|
||||
* Parses a ReadableArray of CSS filter definitions into a chained [RenderEffect].
|
||||
*
|
||||
* @param filters The array of filter definitions, or null
|
||||
* @return A chained RenderEffect representing all filters, or null if no filters provided
|
||||
* @throws IllegalArgumentException if an invalid filter name is encountered
|
||||
*/
|
||||
@JvmStatic
|
||||
fun parseFilters(filters: ReadableArray?): RenderEffect? {
|
||||
filters ?: return null
|
||||
|
||||
+33
@@ -9,9 +9,30 @@ package com.facebook.react.uimanager
|
||||
|
||||
import kotlin.math.abs
|
||||
|
||||
/**
|
||||
* Utility class for comparing floating-point numbers with epsilon-based equality.
|
||||
*
|
||||
* This class provides methods to compare float values while accounting for floating-point precision
|
||||
* issues. Direct equality comparison of floats can be unreliable due to rounding errors in
|
||||
* floating-point arithmetic. This utility uses an epsilon threshold to determine if two float
|
||||
* values are "close enough" to be considered equal.
|
||||
*/
|
||||
public object FloatUtil {
|
||||
|
||||
private const val EPSILON = .00001f
|
||||
|
||||
/**
|
||||
* Compares two float values for equality using an epsilon threshold.
|
||||
*
|
||||
* This method handles special cases:
|
||||
* - If both values are NaN, they are considered equal
|
||||
* - If only one value is NaN, they are not equal
|
||||
* - Otherwise, values are equal if their absolute difference is less than [EPSILON]
|
||||
*
|
||||
* @param f1 the first float value to compare
|
||||
* @param f2 the second float value to compare
|
||||
* @return `true` if the values are equal within the epsilon threshold, `false` otherwise
|
||||
*/
|
||||
@JvmStatic
|
||||
public fun floatsEqual(f1: Float, f2: Float): Boolean {
|
||||
return if (f1.isNaN() || f2.isNaN()) {
|
||||
@@ -19,6 +40,18 @@ public object FloatUtil {
|
||||
} else abs(f2 - f1) < EPSILON
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares two nullable float values for equality using an epsilon threshold.
|
||||
*
|
||||
* This method handles null values:
|
||||
* - If both values are null, they are considered equal
|
||||
* - If only one value is null, they are not equal
|
||||
* - If both values are non-null, delegates to [floatsEqual] with non-null parameters
|
||||
*
|
||||
* @param f1 the first nullable float value to compare
|
||||
* @param f2 the second nullable float value to compare
|
||||
* @return `true` if the values are equal (both null or equal within epsilon), `false` otherwise
|
||||
*/
|
||||
@JvmStatic
|
||||
public fun floatsEqual(f1: Float?, f2: Float?): Boolean {
|
||||
if (f1 == null) {
|
||||
|
||||
+5
-5
@@ -14,15 +14,15 @@ import androidx.annotation.ColorInt
|
||||
import com.facebook.react.modules.i18nmanager.I18nUtil
|
||||
|
||||
internal data class ColorEdges(
|
||||
@ColorInt val left: Int = Color.BLACK,
|
||||
@ColorInt val top: Int = Color.BLACK,
|
||||
@ColorInt val right: Int = Color.BLACK,
|
||||
@ColorInt val bottom: Int = Color.BLACK,
|
||||
@param:ColorInt val left: Int = Color.BLACK,
|
||||
@param:ColorInt val top: Int = Color.BLACK,
|
||||
@param:ColorInt val right: Int = Color.BLACK,
|
||||
@param:ColorInt val bottom: Int = Color.BLACK,
|
||||
)
|
||||
|
||||
@JvmInline
|
||||
internal value class BorderColors(
|
||||
@ColorInt val edgeColors: Array<Int?> = arrayOfNulls<Int?>(LogicalEdge.values().size)
|
||||
@param:ColorInt val edgeColors: Array<Int?> = arrayOfNulls<Int?>(LogicalEdge.values().size)
|
||||
) {
|
||||
|
||||
fun resolve(layoutDirection: Int, context: Context): ColorEdges {
|
||||
|
||||
+1
-1
@@ -18,7 +18,7 @@ import com.facebook.react.bridge.ReadableType
|
||||
public data class BoxShadow(
|
||||
val offsetX: Float,
|
||||
val offsetY: Float,
|
||||
@ColorInt val color: Int? = null,
|
||||
@param:ColorInt val color: Int? = null,
|
||||
val blurRadius: Float? = null,
|
||||
val spreadDistance: Float? = null,
|
||||
val inset: Boolean? = null,
|
||||
|
||||
+12
-3
@@ -83,10 +83,10 @@ public class ReactHorizontalScrollView extends HorizontalScrollView
|
||||
HasSmoothScroll,
|
||||
VirtualViewContainer {
|
||||
|
||||
private static boolean DEBUG_MODE = false && ReactBuildConfig.DEBUG;
|
||||
private static String TAG = ReactHorizontalScrollView.class.getSimpleName();
|
||||
private static final boolean DEBUG_MODE = false && ReactBuildConfig.DEBUG;
|
||||
private static final String TAG = ReactHorizontalScrollView.class.getSimpleName();
|
||||
|
||||
private static int NO_SCROLL_POSITION = Integer.MIN_VALUE;
|
||||
private static final int NO_SCROLL_POSITION = Integer.MIN_VALUE;
|
||||
|
||||
private static @Nullable Field sScrollerField;
|
||||
private static boolean sTriedToGetScrollerField = false;
|
||||
@@ -542,6 +542,15 @@ public class ReactHorizontalScrollView extends HorizontalScrollView
|
||||
if (focused != null && !mPagingEnabled) {
|
||||
scrollToChild(focused);
|
||||
}
|
||||
requestChildFocusWithoutScroll(child, focused);
|
||||
}
|
||||
|
||||
/**
|
||||
* In rare cases where an app overrides the built-in ReactScrollView by overriding it, and also
|
||||
* needs to customize scroll into view on focus behaviors, this protected method can be used to
|
||||
* unblocks such customization.
|
||||
*/
|
||||
protected void requestChildFocusWithoutScroll(View child, View focused) {
|
||||
super.requestChildFocus(child, focused);
|
||||
}
|
||||
|
||||
|
||||
+9
@@ -511,6 +511,15 @@ public class ReactScrollView extends ScrollView
|
||||
if (focused != null) {
|
||||
scrollToChild(focused);
|
||||
}
|
||||
requestChildFocusWithoutScroll(child, focused);
|
||||
}
|
||||
|
||||
/**
|
||||
* In rare cases where an app overrides the built-in ReactScrollView by overriding it, and also
|
||||
* needs to customize scroll into view on focus behaviors, this protected method can be used to
|
||||
* unblocks such customization.
|
||||
*/
|
||||
protected void requestChildFocusWithoutScroll(View child, View focused) {
|
||||
super.requestChildFocus(child, focused);
|
||||
}
|
||||
|
||||
|
||||
+15
-1
@@ -153,6 +153,7 @@ public open class ReactViewGroup public constructor(context: Context?) :
|
||||
private var accessibilityStateChangeListener:
|
||||
AccessibilityManager.AccessibilityStateChangeListener? =
|
||||
null
|
||||
private var focusOnAttach = false
|
||||
|
||||
init {
|
||||
initView()
|
||||
@@ -212,6 +213,9 @@ public open class ReactViewGroup public constructor(context: Context?) :
|
||||
updateBackgroundDrawable(null)
|
||||
|
||||
resetPointerEvents()
|
||||
|
||||
// In case a focus was attempted but the view never attached, reset to false
|
||||
focusOnAttach = false
|
||||
}
|
||||
|
||||
private var _drawingOrderHelper: ViewGroupDrawingOrderHelper? = null
|
||||
@@ -417,10 +421,15 @@ public open class ReactViewGroup public constructor(context: Context?) :
|
||||
}
|
||||
|
||||
internal fun requestFocusFromJS() {
|
||||
super.requestFocus(FOCUS_DOWN, null)
|
||||
if (isAttachedToWindow) {
|
||||
super.requestFocus(FOCUS_DOWN, null)
|
||||
} else {
|
||||
focusOnAttach = true
|
||||
}
|
||||
}
|
||||
|
||||
internal fun clearFocusFromJS() {
|
||||
focusOnAttach = false
|
||||
super.clearFocus()
|
||||
}
|
||||
|
||||
@@ -572,6 +581,11 @@ public open class ReactViewGroup public constructor(context: Context?) :
|
||||
if (_removeClippedSubviews) {
|
||||
updateClippingRect()
|
||||
}
|
||||
|
||||
if (focusOnAttach) {
|
||||
requestFocusFromJS()
|
||||
focusOnAttach = false
|
||||
}
|
||||
}
|
||||
|
||||
private fun customDrawOrderDisabled(): Boolean {
|
||||
|
||||
+16
-5
@@ -187,17 +187,28 @@ public class ReactVirtualView(context: Context) :
|
||||
}
|
||||
|
||||
// If no ScrollView, or ScrollView has disabled removeClippedSubviews, use default behavior
|
||||
if (
|
||||
parentScrollView == null ||
|
||||
!((parentScrollView as ReactClippingViewGroup).removeClippedSubviews ?: false)
|
||||
) {
|
||||
if (parentScrollView == null) {
|
||||
super.updateClippingRect(excludedViews)
|
||||
return
|
||||
}
|
||||
|
||||
val clippingRect = checkNotNull(clippingRect)
|
||||
val parentScrollView = checkNotNull(parentScrollView) as ReactClippingViewGroup
|
||||
|
||||
if (ReactNativeFeatureFlags.enableVirtualViewClippingWithoutScrollViewClipping()) {
|
||||
if (parentScrollView.removeClippedSubviews) {
|
||||
parentScrollView.getClippingRect(clippingRect)
|
||||
} else {
|
||||
(parentScrollView as View).getDrawingRect(clippingRect)
|
||||
}
|
||||
} else {
|
||||
if (!(parentScrollView.removeClippedSubviews ?: false)) {
|
||||
super.updateClippingRect(excludedViews)
|
||||
return
|
||||
}
|
||||
parentScrollView.getClippingRect(clippingRect)
|
||||
}
|
||||
|
||||
(parentScrollView as ReactClippingViewGroup).getClippingRect(clippingRect)
|
||||
clippingRect.intersect(targetRect)
|
||||
clippingRect.offset(-targetRect.left, -targetRect.top)
|
||||
|
||||
|
||||
+17
-5
@@ -208,17 +208,29 @@ public class ReactVirtualViewExperimental(context: Context) :
|
||||
}
|
||||
|
||||
// If no ScrollView, or ScrollView has disabled removeClippedSubviews, use default behavior
|
||||
if (
|
||||
scrollView == null ||
|
||||
!((scrollView as ReactClippingViewGroup).removeClippedSubviews ?: false)
|
||||
) {
|
||||
if (scrollView == null) {
|
||||
super.updateClippingRect(excludedViews)
|
||||
return
|
||||
}
|
||||
|
||||
val clippingRect = checkNotNull(clippingRect)
|
||||
val scrollView = checkNotNull(scrollView) as ReactClippingViewGroup
|
||||
|
||||
if (ReactNativeFeatureFlags.enableVirtualViewClippingWithoutScrollViewClipping()) {
|
||||
if (scrollView.removeClippedSubviews) {
|
||||
scrollView.getClippingRect(clippingRect)
|
||||
} else {
|
||||
(scrollView as View).getDrawingRect(clippingRect)
|
||||
}
|
||||
} else {
|
||||
if (!(scrollView.removeClippedSubviews ?: false)) {
|
||||
super.updateClippingRect(excludedViews)
|
||||
return
|
||||
}
|
||||
|
||||
scrollView.getClippingRect(clippingRect)
|
||||
}
|
||||
|
||||
(scrollView as ReactClippingViewGroup).getClippingRect(clippingRect)
|
||||
clippingRect.intersect(containerRelativeRect)
|
||||
clippingRect.offset(-containerRelativeRect.left, -containerRelativeRect.top)
|
||||
|
||||
|
||||
+43
-1
@@ -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<<48a05f5360c927150021af873e6d52b8>>
|
||||
* @generated SignedSource<<13ed11b5c260fae79048ea80745d22fe>>
|
||||
*/
|
||||
|
||||
/**
|
||||
@@ -219,6 +219,12 @@ class ReactNativeFeatureFlagsJavaProvider
|
||||
return method(javaProvider_);
|
||||
}
|
||||
|
||||
bool enableKeyEvents() override {
|
||||
static const auto method =
|
||||
getReactNativeFeatureFlagsProviderJavaClass()->getMethod<jboolean()>("enableKeyEvents");
|
||||
return method(javaProvider_);
|
||||
}
|
||||
|
||||
bool enableLayoutAnimationsOnAndroid() override {
|
||||
static const auto method =
|
||||
getReactNativeFeatureFlagsProviderJavaClass()->getMethod<jboolean()>("enableLayoutAnimationsOnAndroid");
|
||||
@@ -315,6 +321,12 @@ class ReactNativeFeatureFlagsJavaProvider
|
||||
return method(javaProvider_);
|
||||
}
|
||||
|
||||
bool enableVirtualViewClippingWithoutScrollViewClipping() override {
|
||||
static const auto method =
|
||||
getReactNativeFeatureFlagsProviderJavaClass()->getMethod<jboolean()>("enableVirtualViewClippingWithoutScrollViewClipping");
|
||||
return method(javaProvider_);
|
||||
}
|
||||
|
||||
bool enableVirtualViewContainerStateExperimental() override {
|
||||
static const auto method =
|
||||
getReactNativeFeatureFlagsProviderJavaClass()->getMethod<jboolean()>("enableVirtualViewContainerStateExperimental");
|
||||
@@ -375,6 +387,12 @@ class ReactNativeFeatureFlagsJavaProvider
|
||||
return method(javaProvider_);
|
||||
}
|
||||
|
||||
bool perfIssuesEnabled() override {
|
||||
static const auto method =
|
||||
getReactNativeFeatureFlagsProviderJavaClass()->getMethod<jboolean()>("perfIssuesEnabled");
|
||||
return method(javaProvider_);
|
||||
}
|
||||
|
||||
bool perfMonitorV2Enabled() override {
|
||||
static const auto method =
|
||||
getReactNativeFeatureFlagsProviderJavaClass()->getMethod<jboolean()>("perfMonitorV2Enabled");
|
||||
@@ -673,6 +691,11 @@ bool JReactNativeFeatureFlagsCxxInterop::enableInteropViewManagerClassLookUpOpti
|
||||
return ReactNativeFeatureFlags::enableInteropViewManagerClassLookUpOptimizationIOS();
|
||||
}
|
||||
|
||||
bool JReactNativeFeatureFlagsCxxInterop::enableKeyEvents(
|
||||
facebook::jni::alias_ref<JReactNativeFeatureFlagsCxxInterop> /*unused*/) {
|
||||
return ReactNativeFeatureFlags::enableKeyEvents();
|
||||
}
|
||||
|
||||
bool JReactNativeFeatureFlagsCxxInterop::enableLayoutAnimationsOnAndroid(
|
||||
facebook::jni::alias_ref<JReactNativeFeatureFlagsCxxInterop> /*unused*/) {
|
||||
return ReactNativeFeatureFlags::enableLayoutAnimationsOnAndroid();
|
||||
@@ -753,6 +776,11 @@ bool JReactNativeFeatureFlagsCxxInterop::enableViewRecyclingForView(
|
||||
return ReactNativeFeatureFlags::enableViewRecyclingForView();
|
||||
}
|
||||
|
||||
bool JReactNativeFeatureFlagsCxxInterop::enableVirtualViewClippingWithoutScrollViewClipping(
|
||||
facebook::jni::alias_ref<JReactNativeFeatureFlagsCxxInterop> /*unused*/) {
|
||||
return ReactNativeFeatureFlags::enableVirtualViewClippingWithoutScrollViewClipping();
|
||||
}
|
||||
|
||||
bool JReactNativeFeatureFlagsCxxInterop::enableVirtualViewContainerStateExperimental(
|
||||
facebook::jni::alias_ref<JReactNativeFeatureFlagsCxxInterop> /*unused*/) {
|
||||
return ReactNativeFeatureFlags::enableVirtualViewContainerStateExperimental();
|
||||
@@ -803,6 +831,11 @@ bool JReactNativeFeatureFlagsCxxInterop::overrideBySynchronousMountPropsAtMounti
|
||||
return ReactNativeFeatureFlags::overrideBySynchronousMountPropsAtMountingAndroid();
|
||||
}
|
||||
|
||||
bool JReactNativeFeatureFlagsCxxInterop::perfIssuesEnabled(
|
||||
facebook::jni::alias_ref<JReactNativeFeatureFlagsCxxInterop> /*unused*/) {
|
||||
return ReactNativeFeatureFlags::perfIssuesEnabled();
|
||||
}
|
||||
|
||||
bool JReactNativeFeatureFlagsCxxInterop::perfMonitorV2Enabled(
|
||||
facebook::jni::alias_ref<JReactNativeFeatureFlagsCxxInterop> /*unused*/) {
|
||||
return ReactNativeFeatureFlags::perfMonitorV2Enabled();
|
||||
@@ -1044,6 +1077,9 @@ void JReactNativeFeatureFlagsCxxInterop::registerNatives() {
|
||||
makeNativeMethod(
|
||||
"enableInteropViewManagerClassLookUpOptimizationIOS",
|
||||
JReactNativeFeatureFlagsCxxInterop::enableInteropViewManagerClassLookUpOptimizationIOS),
|
||||
makeNativeMethod(
|
||||
"enableKeyEvents",
|
||||
JReactNativeFeatureFlagsCxxInterop::enableKeyEvents),
|
||||
makeNativeMethod(
|
||||
"enableLayoutAnimationsOnAndroid",
|
||||
JReactNativeFeatureFlagsCxxInterop::enableLayoutAnimationsOnAndroid),
|
||||
@@ -1092,6 +1128,9 @@ void JReactNativeFeatureFlagsCxxInterop::registerNatives() {
|
||||
makeNativeMethod(
|
||||
"enableViewRecyclingForView",
|
||||
JReactNativeFeatureFlagsCxxInterop::enableViewRecyclingForView),
|
||||
makeNativeMethod(
|
||||
"enableVirtualViewClippingWithoutScrollViewClipping",
|
||||
JReactNativeFeatureFlagsCxxInterop::enableVirtualViewClippingWithoutScrollViewClipping),
|
||||
makeNativeMethod(
|
||||
"enableVirtualViewContainerStateExperimental",
|
||||
JReactNativeFeatureFlagsCxxInterop::enableVirtualViewContainerStateExperimental),
|
||||
@@ -1122,6 +1161,9 @@ void JReactNativeFeatureFlagsCxxInterop::registerNatives() {
|
||||
makeNativeMethod(
|
||||
"overrideBySynchronousMountPropsAtMountingAndroid",
|
||||
JReactNativeFeatureFlagsCxxInterop::overrideBySynchronousMountPropsAtMountingAndroid),
|
||||
makeNativeMethod(
|
||||
"perfIssuesEnabled",
|
||||
JReactNativeFeatureFlagsCxxInterop::perfIssuesEnabled),
|
||||
makeNativeMethod(
|
||||
"perfMonitorV2Enabled",
|
||||
JReactNativeFeatureFlagsCxxInterop::perfMonitorV2Enabled),
|
||||
|
||||
+10
-1
@@ -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<<e8bbe1de8eccb3ecea6b9f001de07fd2>>
|
||||
* @generated SignedSource<<1e57bf8252c16fc10bbfcae08710af85>>
|
||||
*/
|
||||
|
||||
/**
|
||||
@@ -120,6 +120,9 @@ class JReactNativeFeatureFlagsCxxInterop
|
||||
static bool enableInteropViewManagerClassLookUpOptimizationIOS(
|
||||
facebook::jni::alias_ref<JReactNativeFeatureFlagsCxxInterop>);
|
||||
|
||||
static bool enableKeyEvents(
|
||||
facebook::jni::alias_ref<JReactNativeFeatureFlagsCxxInterop>);
|
||||
|
||||
static bool enableLayoutAnimationsOnAndroid(
|
||||
facebook::jni::alias_ref<JReactNativeFeatureFlagsCxxInterop>);
|
||||
|
||||
@@ -168,6 +171,9 @@ class JReactNativeFeatureFlagsCxxInterop
|
||||
static bool enableViewRecyclingForView(
|
||||
facebook::jni::alias_ref<JReactNativeFeatureFlagsCxxInterop>);
|
||||
|
||||
static bool enableVirtualViewClippingWithoutScrollViewClipping(
|
||||
facebook::jni::alias_ref<JReactNativeFeatureFlagsCxxInterop>);
|
||||
|
||||
static bool enableVirtualViewContainerStateExperimental(
|
||||
facebook::jni::alias_ref<JReactNativeFeatureFlagsCxxInterop>);
|
||||
|
||||
@@ -198,6 +204,9 @@ class JReactNativeFeatureFlagsCxxInterop
|
||||
static bool overrideBySynchronousMountPropsAtMountingAndroid(
|
||||
facebook::jni::alias_ref<JReactNativeFeatureFlagsCxxInterop>);
|
||||
|
||||
static bool perfIssuesEnabled(
|
||||
facebook::jni::alias_ref<JReactNativeFeatureFlagsCxxInterop>);
|
||||
|
||||
static bool perfMonitorV2Enabled(
|
||||
facebook::jni::alias_ref<JReactNativeFeatureFlagsCxxInterop>);
|
||||
|
||||
|
||||
+7
@@ -120,6 +120,13 @@ void JReactHostInspectorTarget::onSetPausedInDebuggerMessage(
|
||||
}
|
||||
}
|
||||
|
||||
void JReactHostInspectorTarget::unstable_onPerfIssueAdded(
|
||||
const PerfIssuePayload& issue) {
|
||||
static auto method = javaClassStatic()->getMethod<void(local_ref<jstring>)>(
|
||||
"handleNativePerfIssueAdded");
|
||||
method(jobj_, make_jstring(issue.name));
|
||||
}
|
||||
|
||||
void JReactHostInspectorTarget::loadNetworkResource(
|
||||
const jsinspector_modern::LoadNetworkResourceRequest& params,
|
||||
jsinspector_modern::ScopedExecutor<
|
||||
|
||||
+1
@@ -103,6 +103,7 @@ class JReactHostInspectorTarget : public jni::HybridClass<JReactHostInspectorTar
|
||||
jsinspector_modern::HostTargetMetadata getMetadata() override;
|
||||
void onReload(const PageReloadRequest &request) override;
|
||||
void onSetPausedInDebuggerMessage(const OverlaySetPausedInDebuggerMessageRequest &request) override;
|
||||
void unstable_onPerfIssueAdded(const jsinspector_modern::PerfIssuePayload &issue) override;
|
||||
void loadNetworkResource(
|
||||
const jsinspector_modern::LoadNetworkResourceRequest ¶ms,
|
||||
jsinspector_modern::ScopedExecutor<jsinspector_modern::NetworkRequestListener> executor) override;
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
/*
|
||||
* 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 "PerformanceTracerCxxInterop.h"
|
||||
|
||||
#include <fbjni/fbjni.h>
|
||||
|
||||
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void* /*unused*/) {
|
||||
return facebook::jni::initialize(vm, [] {
|
||||
facebook::react::PerformanceTracerCxxInterop::registerNatives();
|
||||
});
|
||||
}
|
||||
+241
@@ -0,0 +1,241 @@
|
||||
/*
|
||||
* 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 "PerformanceTracerCxxInterop.h"
|
||||
|
||||
#include <folly/dynamic.h>
|
||||
#include <jsinspector-modern/tracing/PerformanceTracer.h>
|
||||
#include <react/jni/NativeMap.h>
|
||||
#include <react/jni/ReadableNativeMap.h>
|
||||
#include <react/timing/primitives.h>
|
||||
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
|
||||
namespace facebook::react {
|
||||
|
||||
void TracingStateCallback::onTracingStateChanged(bool isTracing) const {
|
||||
static const auto method =
|
||||
javaClassStatic()->getMethod<void(jboolean)>("onTracingStateChanged");
|
||||
method(self(), static_cast<jboolean>(isTracing));
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
class TracingCallbackRegistry {
|
||||
public:
|
||||
static TracingCallbackRegistry& getInstance() {
|
||||
static TracingCallbackRegistry instance;
|
||||
return instance;
|
||||
}
|
||||
|
||||
void registerCallback(
|
||||
uint32_t subscriptionId,
|
||||
jni::global_ref<jobject> callback) {
|
||||
std::lock_guard<std::mutex> lock(mutex_);
|
||||
callbacks_[subscriptionId] = std::move(callback);
|
||||
}
|
||||
|
||||
void unregisterCallback(uint32_t subscriptionId) {
|
||||
std::lock_guard<std::mutex> lock(mutex_);
|
||||
callbacks_.erase(subscriptionId);
|
||||
}
|
||||
|
||||
jni::global_ref<jobject> getCallback(uint32_t subscriptionId) {
|
||||
std::lock_guard<std::mutex> lock(mutex_);
|
||||
auto it = callbacks_.find(subscriptionId);
|
||||
if (it != callbacks_.end()) {
|
||||
return it->second;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
private:
|
||||
std::mutex mutex_;
|
||||
std::map<uint32_t, jni::global_ref<jobject>> callbacks_;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
void PerformanceTracerCxxInterop::reportMark(
|
||||
jni::alias_ref<PerformanceTracerCxxInterop> /*jthis*/,
|
||||
jni::alias_ref<jstring> name,
|
||||
jlong timestampNanos,
|
||||
jni::alias_ref<ReadableNativeMap::javaobject> detail) {
|
||||
auto& tracer = jsinspector_modern::tracing::PerformanceTracer::getInstance();
|
||||
|
||||
if (!tracer.isTracing()) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::string nameStr = name->toStdString();
|
||||
HighResTimeStamp timestamp = HighResTimeStamp::fromChronoSteadyClockTimePoint(
|
||||
std::chrono::steady_clock::time_point(
|
||||
std::chrono::nanoseconds(timestampNanos)));
|
||||
|
||||
folly::dynamic detailDynamic = nullptr;
|
||||
if (detail) {
|
||||
detailDynamic = detail->cthis()->consume();
|
||||
}
|
||||
|
||||
tracer.reportMark(nameStr, timestamp, std::move(detailDynamic));
|
||||
}
|
||||
|
||||
void PerformanceTracerCxxInterop::reportMeasure(
|
||||
jni::alias_ref<PerformanceTracerCxxInterop> /*jthis*/,
|
||||
jni::alias_ref<jstring> name,
|
||||
jlong startTimestampNanos,
|
||||
jlong durationNanos,
|
||||
jni::alias_ref<ReadableNativeMap::javaobject> detail) {
|
||||
auto& tracer = jsinspector_modern::tracing::PerformanceTracer::getInstance();
|
||||
|
||||
if (!tracer.isTracing()) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::string nameStr = name->toStdString();
|
||||
HighResTimeStamp startTimestamp =
|
||||
HighResTimeStamp::fromChronoSteadyClockTimePoint(
|
||||
std::chrono::steady_clock::time_point(
|
||||
std::chrono::nanoseconds(startTimestampNanos)));
|
||||
HighResDuration duration = HighResDuration::fromNanoseconds(durationNanos);
|
||||
|
||||
folly::dynamic detailDynamic = nullptr;
|
||||
if (detail) {
|
||||
detailDynamic = detail->cthis()->consume();
|
||||
}
|
||||
|
||||
tracer.reportMeasure(
|
||||
nameStr, startTimestamp, duration, std::move(detailDynamic));
|
||||
}
|
||||
|
||||
void PerformanceTracerCxxInterop::reportTimeStamp(
|
||||
jni::alias_ref<PerformanceTracerCxxInterop> /*jthis*/,
|
||||
jni::alias_ref<jstring> name,
|
||||
jlong startTimeNanos,
|
||||
jlong endTimeNanos,
|
||||
jni::alias_ref<jstring> trackName,
|
||||
jni::alias_ref<jstring> trackGroup,
|
||||
jni::alias_ref<jstring> color) {
|
||||
auto& tracer = jsinspector_modern::tracing::PerformanceTracer::getInstance();
|
||||
|
||||
if (!tracer.isTracing()) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::string nameStr = name->toStdString();
|
||||
|
||||
// Convert start timestamp
|
||||
HighResTimeStamp startTimestamp =
|
||||
HighResTimeStamp::fromChronoSteadyClockTimePoint(
|
||||
std::chrono::steady_clock::time_point(
|
||||
std::chrono::nanoseconds(startTimeNanos)));
|
||||
|
||||
// Convert end timestamp
|
||||
HighResTimeStamp endTimestamp =
|
||||
HighResTimeStamp::fromChronoSteadyClockTimePoint(
|
||||
std::chrono::steady_clock::time_point(
|
||||
std::chrono::nanoseconds(endTimeNanos)));
|
||||
|
||||
// Handle optional string parameters
|
||||
std::optional<std::string> trackNameOpt = std::nullopt;
|
||||
if (trackName) {
|
||||
trackNameOpt = trackName->toStdString();
|
||||
}
|
||||
|
||||
std::optional<std::string> trackGroupOpt = std::nullopt;
|
||||
if (trackGroup) {
|
||||
trackGroupOpt = trackGroup->toStdString();
|
||||
}
|
||||
|
||||
// Handle optional color parameter
|
||||
std::optional<jsinspector_modern::tracing::ConsoleTimeStampColor> colorOpt =
|
||||
std::nullopt;
|
||||
if (color) {
|
||||
colorOpt = jsinspector_modern::tracing::getConsoleTimeStampColorFromString(
|
||||
color->toStdString());
|
||||
}
|
||||
|
||||
tracer.reportTimeStamp(
|
||||
nameStr,
|
||||
startTimestamp,
|
||||
endTimestamp,
|
||||
trackNameOpt,
|
||||
trackGroupOpt,
|
||||
colorOpt);
|
||||
}
|
||||
|
||||
jboolean PerformanceTracerCxxInterop::isTracing(
|
||||
jni::alias_ref<PerformanceTracerCxxInterop> /*jthis*/) {
|
||||
return static_cast<jboolean>(
|
||||
jsinspector_modern::tracing::PerformanceTracer::getInstance()
|
||||
.isTracing());
|
||||
}
|
||||
|
||||
jint PerformanceTracerCxxInterop::subscribeToTracingStateChanges(
|
||||
jni::alias_ref<PerformanceTracerCxxInterop> /*jthis*/,
|
||||
jni::alias_ref<TracingStateCallback::javaobject> callback) {
|
||||
auto globalCallback = jni::make_global(callback);
|
||||
|
||||
auto& tracer = jsinspector_modern::tracing::PerformanceTracer::getInstance();
|
||||
|
||||
auto callbackWrapper = std::make_shared<uint32_t>(0);
|
||||
|
||||
uint32_t subscriptionId =
|
||||
tracer.subscribeToTracingStateChanges([callbackWrapper](bool isTracing) {
|
||||
auto callback = TracingCallbackRegistry::getInstance().getCallback(
|
||||
*callbackWrapper);
|
||||
if (callback) {
|
||||
try {
|
||||
jni::ThreadScope::WithClassLoader([&] {
|
||||
auto callbackClass = callback->getClass();
|
||||
auto onTracingStateChangedMethod =
|
||||
callbackClass->getMethod<void(jboolean)>(
|
||||
"onTracingStateChanged");
|
||||
onTracingStateChangedMethod(
|
||||
callback, static_cast<jboolean>(isTracing));
|
||||
});
|
||||
} catch (const std::exception& e) {
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
*callbackWrapper = subscriptionId;
|
||||
TracingCallbackRegistry::getInstance().registerCallback(
|
||||
subscriptionId, globalCallback);
|
||||
|
||||
return static_cast<jint>(subscriptionId);
|
||||
}
|
||||
|
||||
void PerformanceTracerCxxInterop::unsubscribeFromTracingStateChanges(
|
||||
jni::alias_ref<PerformanceTracerCxxInterop> /*jthis*/,
|
||||
jint subscriptionId) {
|
||||
auto& tracer = jsinspector_modern::tracing::PerformanceTracer::getInstance();
|
||||
tracer.unsubscribeFromTracingStateChanges(
|
||||
static_cast<uint32_t>(subscriptionId));
|
||||
TracingCallbackRegistry::getInstance().unregisterCallback(
|
||||
static_cast<uint32_t>(subscriptionId));
|
||||
}
|
||||
|
||||
void PerformanceTracerCxxInterop::registerNatives() {
|
||||
javaClassLocal()->registerNatives(
|
||||
{makeNativeMethod("reportMark", PerformanceTracerCxxInterop::reportMark),
|
||||
makeNativeMethod(
|
||||
"reportMeasure", PerformanceTracerCxxInterop::reportMeasure),
|
||||
makeNativeMethod(
|
||||
"reportTimeStamp", PerformanceTracerCxxInterop::reportTimeStamp),
|
||||
makeNativeMethod("isTracing", PerformanceTracerCxxInterop::isTracing),
|
||||
makeNativeMethod(
|
||||
"subscribeToTracingStateChanges",
|
||||
PerformanceTracerCxxInterop::subscribeToTracingStateChanges),
|
||||
makeNativeMethod(
|
||||
"unsubscribeFromTracingStateChanges",
|
||||
PerformanceTracerCxxInterop::unsubscribeFromTracingStateChanges)});
|
||||
}
|
||||
|
||||
} // namespace facebook::react
|
||||
+63
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <fbjni/fbjni.h>
|
||||
#include <jni.h>
|
||||
#include <react/jni/ReadableNativeMap.h>
|
||||
|
||||
namespace facebook::react {
|
||||
|
||||
class TracingStateCallback : public facebook::jni::JavaClass<TracingStateCallback> {
|
||||
public:
|
||||
static constexpr auto kJavaDescriptor =
|
||||
"Lcom/facebook/react/internal/tracing/PerformanceTracer$TracingStateCallback;";
|
||||
|
||||
void onTracingStateChanged(bool isTracing) const;
|
||||
};
|
||||
|
||||
class PerformanceTracerCxxInterop : public facebook::jni::JavaClass<PerformanceTracerCxxInterop> {
|
||||
public:
|
||||
static constexpr auto kJavaDescriptor = "Lcom/facebook/react/internal/tracing/PerformanceTracer;";
|
||||
|
||||
static void reportMark(
|
||||
facebook::jni::alias_ref<PerformanceTracerCxxInterop> jthis,
|
||||
facebook::jni::alias_ref<jstring> name,
|
||||
jlong timestampNanos,
|
||||
facebook::jni::alias_ref<ReadableNativeMap::javaobject> detail);
|
||||
|
||||
static void reportMeasure(
|
||||
facebook::jni::alias_ref<PerformanceTracerCxxInterop> jthis,
|
||||
facebook::jni::alias_ref<jstring> name,
|
||||
jlong startTimestampNanos,
|
||||
jlong durationNanos,
|
||||
facebook::jni::alias_ref<ReadableNativeMap::javaobject> detail);
|
||||
|
||||
static void reportTimeStamp(
|
||||
facebook::jni::alias_ref<PerformanceTracerCxxInterop> jthis,
|
||||
facebook::jni::alias_ref<jstring> name,
|
||||
jlong startTimeNanos,
|
||||
jlong endTimeNanos,
|
||||
facebook::jni::alias_ref<jstring> trackName,
|
||||
facebook::jni::alias_ref<jstring> trackGroup,
|
||||
facebook::jni::alias_ref<jstring> color);
|
||||
|
||||
static jboolean isTracing(facebook::jni::alias_ref<PerformanceTracerCxxInterop> jthis);
|
||||
|
||||
static jint subscribeToTracingStateChanges(
|
||||
facebook::jni::alias_ref<PerformanceTracerCxxInterop> jthis,
|
||||
facebook::jni::alias_ref<TracingStateCallback::javaobject> callback);
|
||||
|
||||
static void unsubscribeFromTracingStateChanges(
|
||||
facebook::jni::alias_ref<PerformanceTracerCxxInterop> jthis,
|
||||
jint subscriptionId);
|
||||
|
||||
static void registerNatives();
|
||||
};
|
||||
|
||||
} // namespace facebook::react
|
||||
@@ -53,6 +53,14 @@ import UIKit
|
||||
containerViewModel.saturationAmount = CGFloat(saturation.floatValue)
|
||||
}
|
||||
|
||||
@objc public func updateContrast(_ contrast: NSNumber) {
|
||||
containerViewModel.contrastAmount = CGFloat(contrast.floatValue)
|
||||
}
|
||||
|
||||
@objc public func updateHueRotate(_ degrees: NSNumber) {
|
||||
containerViewModel.hueRotationDegrees = CGFloat(degrees.floatValue)
|
||||
}
|
||||
|
||||
@objc public func updateLayout(withBounds bounds: CGRect) {
|
||||
hostingController?.view.frame = bounds
|
||||
containerViewModel.contentView?.frame = bounds
|
||||
@@ -66,6 +74,8 @@ import UIKit
|
||||
containerViewModel.shadowY = 0
|
||||
containerViewModel.shadowColor = Color.clear
|
||||
containerViewModel.saturationAmount = 1
|
||||
containerViewModel.contrastAmount = 1
|
||||
containerViewModel.hueRotationDegrees = 0
|
||||
}
|
||||
}
|
||||
|
||||
@@ -85,6 +95,12 @@ class ContainerViewModel: ObservableObject {
|
||||
// saturation filter properties
|
||||
@Published var saturationAmount: CGFloat = 1
|
||||
|
||||
// contrast filter properties
|
||||
@Published var contrastAmount: CGFloat = 1
|
||||
|
||||
// hue-rotate filter properties
|
||||
@Published var hueRotationDegrees: CGFloat = 0
|
||||
|
||||
@Published var contentView: UIView?
|
||||
}
|
||||
|
||||
@@ -98,6 +114,8 @@ struct SwiftUIContainerView: View {
|
||||
.grayscale(viewModel.grayscale)
|
||||
.shadow(color: viewModel.shadowColor, radius: viewModel.shadowRadius, x: viewModel.shadowX, y: viewModel.shadowY)
|
||||
.saturation(viewModel.saturationAmount)
|
||||
.contrast(viewModel.contrastAmount)
|
||||
.hueRotation(.degrees(viewModel.hueRotationDegrees))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,6 +17,8 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
- (void)updateGrayscale:(NSNumber *)grayscale;
|
||||
- (void)updateDropShadow:(NSNumber *)standardDeviation x:(NSNumber *)x y:(NSNumber *)y color:(UIColor *)color;
|
||||
- (void)updateSaturation:(NSNumber *)saturation;
|
||||
- (void)updateContrast:(NSNumber *)contrast;
|
||||
- (void)updateHueRotate:(NSNumber *)degrees;
|
||||
- (void)updateContentView:(UIView *)view;
|
||||
- (UIView *_Nullable)hostingView;
|
||||
- (void)resetStyles;
|
||||
|
||||
@@ -58,6 +58,16 @@
|
||||
[self.swiftContainerView updateSaturation:saturation];
|
||||
}
|
||||
|
||||
- (void)updateContrast:(NSNumber *)contrast
|
||||
{
|
||||
[self.swiftContainerView updateContrast:contrast];
|
||||
}
|
||||
|
||||
- (void)updateHueRotate:(NSNumber *)degrees
|
||||
{
|
||||
[self.swiftContainerView updateHueRotate:degrees];
|
||||
}
|
||||
|
||||
- (void)updateDropShadow:(NSNumber *)standardDeviation x:(NSNumber *)x y:(NSNumber *)y color:(UIColor *)color
|
||||
{
|
||||
[self.swiftContainerView updateDropShadowWithStandardDeviation:standardDeviation x:x y:y color:color];
|
||||
|
||||
@@ -1523,6 +1523,7 @@ jsi::Value JSCRuntime::createValue(JSValueRef value) const {
|
||||
}
|
||||
case kJSTypeSymbol:
|
||||
return jsi::Value(createSymbol(value));
|
||||
case kJSTypeBigInt:
|
||||
default:
|
||||
// WHAT ARE YOU
|
||||
abort();
|
||||
|
||||
@@ -206,6 +206,9 @@ std::shared_ptr<HostTarget> HostTarget::create(
|
||||
VoidExecutor executor) {
|
||||
std::shared_ptr<HostTarget> hostTarget{new HostTarget(delegate)};
|
||||
hostTarget->setExecutor(std::move(executor));
|
||||
if (InspectorFlags::getInstance().getPerfIssuesEnabled()) {
|
||||
hostTarget->installPerfIssuesBinding();
|
||||
}
|
||||
return hostTarget;
|
||||
}
|
||||
|
||||
@@ -289,6 +292,17 @@ void HostTarget::sendCommand(HostCommand command) {
|
||||
});
|
||||
}
|
||||
|
||||
void HostTarget::installPerfIssuesBinding() {
|
||||
perfMonitorUpdateHandler_ =
|
||||
std::make_unique<PerfMonitorUpdateHandler>(delegate_);
|
||||
perfMetricsBinding_ = std::make_unique<HostRuntimeBinding>(
|
||||
*this, // Used immediately
|
||||
"__react_native_perf_issues_reporter",
|
||||
[this](const std::string& message) {
|
||||
perfMonitorUpdateHandler_->handlePerfIssueAdded(message);
|
||||
});
|
||||
}
|
||||
|
||||
HostTargetController::HostTargetController(HostTarget& target)
|
||||
: target_(target) {}
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
#include "InspectorInterfaces.h"
|
||||
#include "InstanceTarget.h"
|
||||
#include "NetworkIOAgent.h"
|
||||
#include "PerfMonitorV2.h"
|
||||
#include "ScopedExecutor.h"
|
||||
#include "WeakList.h"
|
||||
|
||||
@@ -126,6 +127,12 @@ class HostTargetDelegate : public LoadNetworkResourceDelegate {
|
||||
*/
|
||||
virtual void onSetPausedInDebuggerMessage(const OverlaySetPausedInDebuggerMessageRequest &request) = 0;
|
||||
|
||||
/**
|
||||
* [Experimental] Called when the runtime has new data for the V2 Perf
|
||||
* Monitor overlay. This is called on the inspector thread.
|
||||
*/
|
||||
virtual void unstable_onPerfIssueAdded(const PerfIssuePayload & /*issue*/) {}
|
||||
|
||||
/**
|
||||
* Called by NetworkIOAgent on handling a `Network.loadNetworkResource` CDP
|
||||
* request. Platform implementations should override this to perform a
|
||||
@@ -166,6 +173,13 @@ class HostTargetController final {
|
||||
|
||||
bool hasInstance() const;
|
||||
|
||||
/**
|
||||
* [Experimental] Install a runtime binding subscribing to new Performance
|
||||
* Issues, which we broadcast to the V2 Perf Monitor overlay via
|
||||
* \ref HostTargetDelegate::unstable_onPerfIssueAdded.
|
||||
*/
|
||||
void installPerfIssuesBinding();
|
||||
|
||||
/**
|
||||
* Increments the target's pause overlay counter. The counter represents the
|
||||
* exact number of Agents that have (concurrently) requested the pause
|
||||
@@ -325,6 +339,7 @@ class JSINSPECTOR_EXPORT HostTarget : public EnableExecutorFromThis<HostTarget>
|
||||
std::shared_ptr<ExecutionContextManager> executionContextManager_;
|
||||
std::shared_ptr<InstanceTarget> currentInstance_{nullptr};
|
||||
std::unique_ptr<HostCommandSender> commandSender_;
|
||||
std::unique_ptr<PerfMonitorUpdateHandler> perfMonitorUpdateHandler_;
|
||||
std::unique_ptr<HostRuntimeBinding> perfMetricsBinding_;
|
||||
|
||||
/**
|
||||
@@ -345,6 +360,13 @@ class JSINSPECTOR_EXPORT HostTarget : public EnableExecutorFromThis<HostTarget>
|
||||
return currentInstance_ != nullptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* [Experimental] Install a runtime binding subscribing to new Peformance
|
||||
* Issues, which we broadcast to the V2 Perf Monitor overlay via
|
||||
* \ref HostTargetDelegate::unstable_onPerfMonitorUpdate.
|
||||
*/
|
||||
void installPerfIssuesBinding();
|
||||
|
||||
// Necessary to allow HostAgent to access HostTarget's internals in a
|
||||
// controlled way (i.e. only HostTargetController gets friend access, while
|
||||
// HostAgent itself doesn't).
|
||||
|
||||
@@ -33,6 +33,10 @@ bool InspectorFlags::getNetworkInspectionEnabled() const {
|
||||
return loadFlagsAndAssertUnchanged().networkInspectionEnabled;
|
||||
}
|
||||
|
||||
bool InspectorFlags::getPerfIssuesEnabled() const {
|
||||
return loadFlagsAndAssertUnchanged().perfIssuesEnabled;
|
||||
}
|
||||
|
||||
void InspectorFlags::dangerouslyResetFlags() {
|
||||
*this = InspectorFlags{};
|
||||
}
|
||||
@@ -59,6 +63,7 @@ const InspectorFlags::Values& InspectorFlags::loadFlagsAndAssertUnchanged()
|
||||
.networkInspectionEnabled =
|
||||
ReactNativeFeatureFlags::enableBridgelessArchitecture() &&
|
||||
ReactNativeFeatureFlags::fuseboxNetworkInspectionEnabled(),
|
||||
.perfIssuesEnabled = ReactNativeFeatureFlags::perfIssuesEnabled(),
|
||||
};
|
||||
|
||||
if (cachedValues_.has_value() && !inconsistentFlagsStateLogged_) {
|
||||
|
||||
@@ -35,6 +35,11 @@ class InspectorFlags {
|
||||
*/
|
||||
bool getNetworkInspectionEnabled() const;
|
||||
|
||||
/**
|
||||
* Flag determining if the V2 in-app Performance Monitor is enabled.
|
||||
*/
|
||||
bool getPerfIssuesEnabled() const;
|
||||
|
||||
/**
|
||||
* Forcibly disable the main `getFuseboxEnabled()` flag. This should ONLY be
|
||||
* used by `ReactInstanceIntegrationTest`.
|
||||
@@ -52,6 +57,7 @@ class InspectorFlags {
|
||||
bool fuseboxEnabled;
|
||||
bool isProfilingBuild;
|
||||
bool networkInspectionEnabled;
|
||||
bool perfIssuesEnabled;
|
||||
bool operator==(const Values &) const = default;
|
||||
};
|
||||
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* 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 "PerfMonitorV2.h"
|
||||
#include "HostTarget.h"
|
||||
|
||||
#include <folly/json.h>
|
||||
#include <react/timing/primitives.h>
|
||||
|
||||
namespace facebook::react::jsinspector_modern {
|
||||
|
||||
void PerfMonitorUpdateHandler::handlePerfIssueAdded(
|
||||
const std::string& message) {
|
||||
auto payload = folly::parseJson(message);
|
||||
|
||||
if (payload.isObject()) {
|
||||
delegate_.unstable_onPerfIssueAdded(
|
||||
PerfIssuePayload{
|
||||
.name = payload["name"].asString(),
|
||||
.severity = payload["severity"].asString(),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace facebook::react::jsinspector_modern
|
||||
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* 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 {
|
||||
|
||||
class HostTargetDelegate;
|
||||
|
||||
struct PerfIssuePayload {
|
||||
std::string name;
|
||||
std::string severity;
|
||||
};
|
||||
|
||||
/**
|
||||
* [Experimental] Utility to handle performance metrics updates received from
|
||||
* the runtime and forward update events to the V2 Perf Monitor UI.
|
||||
*/
|
||||
class PerfMonitorUpdateHandler {
|
||||
public:
|
||||
explicit PerfMonitorUpdateHandler(HostTargetDelegate &delegate) : delegate_(delegate) {}
|
||||
|
||||
/**
|
||||
* Handle a new "__react_native_perf_issues_reporter" message.
|
||||
*/
|
||||
void handlePerfIssueAdded(const std::string &message);
|
||||
|
||||
private:
|
||||
HostTargetDelegate &delegate_;
|
||||
};
|
||||
|
||||
} // namespace facebook::react::jsinspector_modern
|
||||
@@ -342,10 +342,7 @@ class JSINSPECTOR_EXPORT RuntimeTarget : public EnableExecutorFromThis<RuntimeTa
|
||||
* sessions, or when the only Agent that had this domain enabled has
|
||||
* disconnected.
|
||||
*/
|
||||
std::pair<bool, bool> processDomainChange(
|
||||
Domain domain,
|
||||
bool enabled,
|
||||
const RuntimeAgent& notifyingAgent);
|
||||
std::pair<bool, bool> processDomainChange(Domain domain, bool enabled, const RuntimeAgent ¬ifyingAgent);
|
||||
|
||||
/**
|
||||
* Checks whether the given domain is enabled in at least one session
|
||||
|
||||
@@ -467,9 +467,18 @@ void consoleTimeStamp(
|
||||
}
|
||||
}
|
||||
|
||||
std::optional<folly::dynamic> detail;
|
||||
if (performanceTracer.isTracing() && argumentsCount >= 7) {
|
||||
const jsi::Value& detailArgument = arguments[6];
|
||||
if (detailArgument.isObject()) {
|
||||
detail =
|
||||
tracing::getConsoleTimeStampDetailFromObject(runtime, detailArgument);
|
||||
}
|
||||
}
|
||||
|
||||
if (performanceTracer.isTracing()) {
|
||||
performanceTracer.reportTimeStamp(
|
||||
label, start, end, trackName, trackGroup, color);
|
||||
label, start, end, trackName, trackGroup, color, std::move(detail));
|
||||
}
|
||||
|
||||
if (ReactPerfettoLogger::isTracing()) {
|
||||
|
||||
@@ -18,6 +18,7 @@ target_include_directories(jsinspector_tracing PUBLIC ${REACT_COMMON_DIR})
|
||||
|
||||
target_link_libraries(jsinspector_tracing
|
||||
folly_runtime
|
||||
jsi
|
||||
jsinspector_network
|
||||
oscompat
|
||||
react_timing
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
/*
|
||||
* 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 "ConsoleTimeStamp.h"
|
||||
|
||||
namespace facebook::react::jsinspector_modern::tracing {
|
||||
|
||||
std::optional<folly::dynamic> getConsoleTimeStampDetailFromObject(
|
||||
jsi::Runtime& runtime,
|
||||
const jsi::Value& detailValue) {
|
||||
try {
|
||||
return jsi::dynamicFromValue(runtime, detailValue);
|
||||
} catch (jsi::JSIException&) {
|
||||
return std::nullopt;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace facebook::react::jsinspector_modern::tracing
|
||||
@@ -7,6 +7,8 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <jsi/JSIDynamic.h>
|
||||
#include <jsi/jsi.h>
|
||||
#include <react/timing/primitives.h>
|
||||
|
||||
#include <cassert>
|
||||
@@ -96,4 +98,6 @@ inline std::optional<ConsoleTimeStampColor> getConsoleTimeStampColorFromString(c
|
||||
}
|
||||
};
|
||||
|
||||
std::optional<folly::dynamic> getConsoleTimeStampDetailFromObject(jsi::Runtime &runtime, const jsi::Value &detailValue);
|
||||
|
||||
}; // namespace facebook::react::jsinspector_modern::tracing
|
||||
|
||||
+63
-11
@@ -57,26 +57,39 @@ bool PerformanceTracer::startTracing(HighResDuration maxDuration) {
|
||||
|
||||
bool PerformanceTracer::startTracingImpl(
|
||||
std::optional<HighResDuration> maxDuration) {
|
||||
std::lock_guard lock(mutex_);
|
||||
std::vector<TracingStateCallback> callbacksToNotify;
|
||||
|
||||
if (tracingAtomic_) {
|
||||
return false;
|
||||
{
|
||||
std::lock_guard lock(mutex_);
|
||||
|
||||
if (tracingAtomic_) {
|
||||
return false;
|
||||
}
|
||||
|
||||
tracingAtomic_ = true;
|
||||
|
||||
if (maxDuration && *maxDuration < MIN_VALUE_FOR_MAX_TRACE_DURATION_OPTION) {
|
||||
throw std::invalid_argument("maxDuration should be at least 1 second");
|
||||
}
|
||||
|
||||
currentTraceStartTime_ = HighResTimeStamp::now();
|
||||
currentTraceMaxDuration_ = maxDuration;
|
||||
|
||||
for (const auto& [id, callback] : tracingStateCallbacks_) {
|
||||
callbacksToNotify.push_back(callback);
|
||||
}
|
||||
}
|
||||
|
||||
tracingAtomic_ = true;
|
||||
|
||||
if (maxDuration && *maxDuration < MIN_VALUE_FOR_MAX_TRACE_DURATION_OPTION) {
|
||||
throw std::invalid_argument("maxDuration should be at least 1 second");
|
||||
for (const auto& callback : callbacksToNotify) {
|
||||
callback(true);
|
||||
}
|
||||
|
||||
currentTraceStartTime_ = HighResTimeStamp::now();
|
||||
currentTraceMaxDuration_ = maxDuration;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
std::optional<std::vector<TraceEvent>> PerformanceTracer::stopTracing() {
|
||||
std::vector<TraceEvent> events;
|
||||
std::vector<TracingStateCallback> callbacksToNotify;
|
||||
|
||||
auto currentTraceEndTime = HighResTimeStamp::now();
|
||||
|
||||
@@ -87,6 +100,21 @@ std::optional<std::vector<TraceEvent>> PerformanceTracer::stopTracing() {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
// Collect callbacks before disabling tracing
|
||||
for (const auto& [id, callback] : tracingStateCallbacks_) {
|
||||
callbacksToNotify.push_back(callback);
|
||||
}
|
||||
}
|
||||
|
||||
// Notify callbacks while tracing is still enabled, so they can send final
|
||||
// events
|
||||
for (const auto& callback : callbacksToNotify) {
|
||||
callback(false);
|
||||
}
|
||||
|
||||
{
|
||||
std::lock_guard lock(mutex_);
|
||||
|
||||
tracingAtomic_ = false;
|
||||
performanceMeasureCount_ = 0;
|
||||
|
||||
@@ -129,6 +157,7 @@ std::optional<std::vector<TraceEvent>> PerformanceTracer::stopTracing() {
|
||||
});
|
||||
|
||||
currentTraceMaxDuration_ = std::nullopt;
|
||||
|
||||
return events;
|
||||
}
|
||||
|
||||
@@ -184,7 +213,8 @@ void PerformanceTracer::reportTimeStamp(
|
||||
std::optional<ConsoleTimeStampEntry> end,
|
||||
std::optional<std::string> trackName,
|
||||
std::optional<std::string> trackGroup,
|
||||
std::optional<ConsoleTimeStampColor> color) {
|
||||
std::optional<ConsoleTimeStampColor> color,
|
||||
std::optional<folly::dynamic> detail) {
|
||||
if (!tracingAtomic_) {
|
||||
return;
|
||||
}
|
||||
@@ -202,6 +232,7 @@ void PerformanceTracer::reportTimeStamp(
|
||||
.trackName = std::move(trackName),
|
||||
.trackGroup = std::move(trackGroup),
|
||||
.color = std::move(color),
|
||||
.detail = std::move(detail),
|
||||
.threadId = getCurrentThreadId(),
|
||||
});
|
||||
}
|
||||
@@ -622,6 +653,13 @@ void PerformanceTracer::enqueueTraceEventsFromPerformanceTracerEvent(
|
||||
if (event.color) {
|
||||
data["color"] = consoleTimeStampColorToString(*event.color);
|
||||
}
|
||||
if (event.detail) {
|
||||
folly::dynamic devtoolsDetail = folly::dynamic::object();
|
||||
for (const auto& [key, value] : event.detail->items()) {
|
||||
devtoolsDetail[key] = value;
|
||||
}
|
||||
data["devtools"] = folly::toJson(devtoolsDetail);
|
||||
}
|
||||
|
||||
events.emplace_back(
|
||||
TraceEvent{
|
||||
@@ -703,4 +741,18 @@ void PerformanceTracer::enqueueTraceEventsFromPerformanceTracerEvent(
|
||||
std::move(event));
|
||||
}
|
||||
|
||||
uint32_t PerformanceTracer::subscribeToTracingStateChanges(
|
||||
TracingStateCallback callback) {
|
||||
std::lock_guard lock(mutex_);
|
||||
uint32_t subscriptionId = nextCallbackId_++;
|
||||
tracingStateCallbacks_[subscriptionId] = std::move(callback);
|
||||
return subscriptionId;
|
||||
}
|
||||
|
||||
void PerformanceTracer::unsubscribeFromTracingStateChanges(
|
||||
uint32_t subscriptionId) {
|
||||
std::lock_guard lock(mutex_);
|
||||
tracingStateCallbacks_.erase(subscriptionId);
|
||||
}
|
||||
|
||||
} // namespace facebook::react::jsinspector_modern::tracing
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
|
||||
#include <folly/dynamic.h>
|
||||
#include <atomic>
|
||||
#include <functional>
|
||||
#include <map>
|
||||
#include <mutex>
|
||||
#include <optional>
|
||||
@@ -95,7 +96,8 @@ class PerformanceTracer {
|
||||
std::optional<ConsoleTimeStampEntry> end = std::nullopt,
|
||||
std::optional<std::string> trackName = std::nullopt,
|
||||
std::optional<std::string> trackGroup = std::nullopt,
|
||||
std::optional<ConsoleTimeStampColor> color = std::nullopt);
|
||||
std::optional<ConsoleTimeStampColor> color = std::nullopt,
|
||||
std::optional<folly::dynamic> detail = std::nullopt);
|
||||
|
||||
/**
|
||||
* Record an Event Loop tick, which will be represented as an Event Loop task
|
||||
@@ -182,6 +184,29 @@ class PerformanceTracer {
|
||||
HighResTimeStamp chunkTimestamp,
|
||||
TraceEventProfileChunk &&traceEventProfileChunk);
|
||||
|
||||
/**
|
||||
* Callback function type for tracing state changes.
|
||||
* @param isTracing true if tracing has started, false if tracing has stopped
|
||||
*/
|
||||
using TracingStateCallback = std::function<void(bool isTracing)>;
|
||||
|
||||
/**
|
||||
* Subscribe to tracing state changes (start/stop events).
|
||||
* Tracing start state is reported after tracing has started, so callbacks can
|
||||
* report events immediately.
|
||||
* Tracing stop state is reported before tracing has stopped, so callbacks
|
||||
* can report final events.
|
||||
* @param callback Function to call when tracing starts or stops
|
||||
* @return A unique identifier for the subscription that can be used to unsubscribe
|
||||
*/
|
||||
uint32_t subscribeToTracingStateChanges(TracingStateCallback callback);
|
||||
|
||||
/**
|
||||
* Unsubscribe from tracing state changes.
|
||||
* @param subscriptionId The identifier returned from subscribeToTracingStateChanges
|
||||
*/
|
||||
void unsubscribeFromTracingStateChanges(uint32_t subscriptionId);
|
||||
|
||||
private:
|
||||
PerformanceTracer();
|
||||
PerformanceTracer(const PerformanceTracer &) = delete;
|
||||
@@ -228,6 +253,7 @@ class PerformanceTracer {
|
||||
std::optional<std::string> trackName;
|
||||
std::optional<std::string> trackGroup;
|
||||
std::optional<ConsoleTimeStampColor> color;
|
||||
std::optional<folly::dynamic> detail;
|
||||
ThreadId threadId;
|
||||
HighResTimeStamp createdAt = HighResTimeStamp::now();
|
||||
};
|
||||
@@ -316,6 +342,10 @@ class PerformanceTracer {
|
||||
*/
|
||||
std::mutex mutex_;
|
||||
|
||||
// Callback management
|
||||
std::map<uint32_t, TracingStateCallback> tracingStateCallbacks_;
|
||||
uint32_t nextCallbackId_{0};
|
||||
|
||||
bool startTracingImpl(std::optional<HighResDuration> maxDuration = std::nullopt);
|
||||
|
||||
std::vector<TraceEvent> collectEventsAndClearBuffers(HighResTimeStamp currentTraceEndTime);
|
||||
|
||||
+1
@@ -44,6 +44,7 @@ Pod::Spec.new do |s|
|
||||
resolve_use_frameworks(s, header_mappings_dir: "../..", module_name: module_name)
|
||||
|
||||
add_dependency(s, "React-jsinspectornetwork", :framework_name => 'jsinspector_modernnetwork')
|
||||
s.dependency "React-jsi"
|
||||
s.dependency "React-oscompat"
|
||||
s.dependency "React-timing"
|
||||
|
||||
|
||||
@@ -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<<0554340092d31b5431e201f570599ab5>>
|
||||
* @generated SignedSource<<5d596cc470e66861d7c1b2ffbb15b268>>
|
||||
*/
|
||||
|
||||
/**
|
||||
@@ -146,6 +146,10 @@ bool ReactNativeFeatureFlags::enableInteropViewManagerClassLookUpOptimizationIOS
|
||||
return getAccessor().enableInteropViewManagerClassLookUpOptimizationIOS();
|
||||
}
|
||||
|
||||
bool ReactNativeFeatureFlags::enableKeyEvents() {
|
||||
return getAccessor().enableKeyEvents();
|
||||
}
|
||||
|
||||
bool ReactNativeFeatureFlags::enableLayoutAnimationsOnAndroid() {
|
||||
return getAccessor().enableLayoutAnimationsOnAndroid();
|
||||
}
|
||||
@@ -210,6 +214,10 @@ bool ReactNativeFeatureFlags::enableViewRecyclingForView() {
|
||||
return getAccessor().enableViewRecyclingForView();
|
||||
}
|
||||
|
||||
bool ReactNativeFeatureFlags::enableVirtualViewClippingWithoutScrollViewClipping() {
|
||||
return getAccessor().enableVirtualViewClippingWithoutScrollViewClipping();
|
||||
}
|
||||
|
||||
bool ReactNativeFeatureFlags::enableVirtualViewContainerStateExperimental() {
|
||||
return getAccessor().enableVirtualViewContainerStateExperimental();
|
||||
}
|
||||
@@ -250,6 +258,10 @@ bool ReactNativeFeatureFlags::overrideBySynchronousMountPropsAtMountingAndroid()
|
||||
return getAccessor().overrideBySynchronousMountPropsAtMountingAndroid();
|
||||
}
|
||||
|
||||
bool ReactNativeFeatureFlags::perfIssuesEnabled() {
|
||||
return getAccessor().perfIssuesEnabled();
|
||||
}
|
||||
|
||||
bool ReactNativeFeatureFlags::perfMonitorV2Enabled() {
|
||||
return getAccessor().perfMonitorV2Enabled();
|
||||
}
|
||||
|
||||
@@ -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<<98a77cdecfd3e6d42f03b2b4ba3d8c88>>
|
||||
* @generated SignedSource<<41492e85e1feeb20d2e3e60b6cc6cbe7>>
|
||||
*/
|
||||
|
||||
/**
|
||||
@@ -189,6 +189,11 @@ class ReactNativeFeatureFlags {
|
||||
*/
|
||||
RN_EXPORT static bool enableInteropViewManagerClassLookUpOptimizationIOS();
|
||||
|
||||
/**
|
||||
* Enables key up/down/press events to be sent to JS from components
|
||||
*/
|
||||
RN_EXPORT static bool enableKeyEvents();
|
||||
|
||||
/**
|
||||
* When enabled, LayoutAnimations API will animate state changes on Android.
|
||||
*/
|
||||
@@ -269,6 +274,11 @@ class ReactNativeFeatureFlags {
|
||||
*/
|
||||
RN_EXPORT static bool enableViewRecyclingForView();
|
||||
|
||||
/**
|
||||
* Set clipping to drawingRect of ScrollView.
|
||||
*/
|
||||
RN_EXPORT static bool enableVirtualViewClippingWithoutScrollViewClipping();
|
||||
|
||||
/**
|
||||
* Enables the experimental version of `VirtualViewContainerState`.
|
||||
*/
|
||||
@@ -319,6 +329,11 @@ class ReactNativeFeatureFlags {
|
||||
*/
|
||||
RN_EXPORT static bool overrideBySynchronousMountPropsAtMountingAndroid();
|
||||
|
||||
/**
|
||||
* Enable reporting Performance Issues (`detail.rnPerfIssue`). Displayed in the V2 Performance Monitor and the "Performance Issues" sub-panel in DevTools.
|
||||
*/
|
||||
RN_EXPORT static bool perfIssuesEnabled();
|
||||
|
||||
/**
|
||||
* Enable the V2 in-app Performance Monitor. This flag is global and should not be changed across React Host lifetimes.
|
||||
*/
|
||||
|
||||
+105
-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<<4eba223705b2d24f0360c6da1239b9a0>>
|
||||
* @generated SignedSource<<cf152ea3a4e9635a71d2794a3139dadb>>
|
||||
*/
|
||||
|
||||
/**
|
||||
@@ -569,6 +569,24 @@ bool ReactNativeFeatureFlagsAccessor::enableInteropViewManagerClassLookUpOptimiz
|
||||
return flagValue.value();
|
||||
}
|
||||
|
||||
bool ReactNativeFeatureFlagsAccessor::enableKeyEvents() {
|
||||
auto flagValue = enableKeyEvents_.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(30, "enableKeyEvents");
|
||||
|
||||
flagValue = currentProvider_->enableKeyEvents();
|
||||
enableKeyEvents_ = flagValue;
|
||||
}
|
||||
|
||||
return flagValue.value();
|
||||
}
|
||||
|
||||
bool ReactNativeFeatureFlagsAccessor::enableLayoutAnimationsOnAndroid() {
|
||||
auto flagValue = enableLayoutAnimationsOnAndroid_.load();
|
||||
|
||||
@@ -578,7 +596,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(30, "enableLayoutAnimationsOnAndroid");
|
||||
markFlagAsAccessed(31, "enableLayoutAnimationsOnAndroid");
|
||||
|
||||
flagValue = currentProvider_->enableLayoutAnimationsOnAndroid();
|
||||
enableLayoutAnimationsOnAndroid_ = flagValue;
|
||||
@@ -596,7 +614,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(31, "enableLayoutAnimationsOnIOS");
|
||||
markFlagAsAccessed(32, "enableLayoutAnimationsOnIOS");
|
||||
|
||||
flagValue = currentProvider_->enableLayoutAnimationsOnIOS();
|
||||
enableLayoutAnimationsOnIOS_ = flagValue;
|
||||
@@ -614,7 +632,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(32, "enableMainQueueCoordinatorOnIOS");
|
||||
markFlagAsAccessed(33, "enableMainQueueCoordinatorOnIOS");
|
||||
|
||||
flagValue = currentProvider_->enableMainQueueCoordinatorOnIOS();
|
||||
enableMainQueueCoordinatorOnIOS_ = flagValue;
|
||||
@@ -632,7 +650,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(33, "enableModuleArgumentNSNullConversionIOS");
|
||||
markFlagAsAccessed(34, "enableModuleArgumentNSNullConversionIOS");
|
||||
|
||||
flagValue = currentProvider_->enableModuleArgumentNSNullConversionIOS();
|
||||
enableModuleArgumentNSNullConversionIOS_ = flagValue;
|
||||
@@ -650,7 +668,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(34, "enableNativeCSSParsing");
|
||||
markFlagAsAccessed(35, "enableNativeCSSParsing");
|
||||
|
||||
flagValue = currentProvider_->enableNativeCSSParsing();
|
||||
enableNativeCSSParsing_ = flagValue;
|
||||
@@ -668,7 +686,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(35, "enableNetworkEventReporting");
|
||||
markFlagAsAccessed(36, "enableNetworkEventReporting");
|
||||
|
||||
flagValue = currentProvider_->enableNetworkEventReporting();
|
||||
enableNetworkEventReporting_ = flagValue;
|
||||
@@ -686,7 +704,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(36, "enablePreparedTextLayout");
|
||||
markFlagAsAccessed(37, "enablePreparedTextLayout");
|
||||
|
||||
flagValue = currentProvider_->enablePreparedTextLayout();
|
||||
enablePreparedTextLayout_ = flagValue;
|
||||
@@ -704,7 +722,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(37, "enablePropsUpdateReconciliationAndroid");
|
||||
markFlagAsAccessed(38, "enablePropsUpdateReconciliationAndroid");
|
||||
|
||||
flagValue = currentProvider_->enablePropsUpdateReconciliationAndroid();
|
||||
enablePropsUpdateReconciliationAndroid_ = flagValue;
|
||||
@@ -722,7 +740,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(38, "enableResourceTimingAPI");
|
||||
markFlagAsAccessed(39, "enableResourceTimingAPI");
|
||||
|
||||
flagValue = currentProvider_->enableResourceTimingAPI();
|
||||
enableResourceTimingAPI_ = flagValue;
|
||||
@@ -740,7 +758,7 @@ bool ReactNativeFeatureFlagsAccessor::enableSwiftUIBasedFilters() {
|
||||
// be accessing the provider multiple times but the end state of this
|
||||
// instance and the returned flag value would be the same.
|
||||
|
||||
markFlagAsAccessed(39, "enableSwiftUIBasedFilters");
|
||||
markFlagAsAccessed(40, "enableSwiftUIBasedFilters");
|
||||
|
||||
flagValue = currentProvider_->enableSwiftUIBasedFilters();
|
||||
enableSwiftUIBasedFilters_ = flagValue;
|
||||
@@ -758,7 +776,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(40, "enableViewCulling");
|
||||
markFlagAsAccessed(41, "enableViewCulling");
|
||||
|
||||
flagValue = currentProvider_->enableViewCulling();
|
||||
enableViewCulling_ = flagValue;
|
||||
@@ -776,7 +794,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(41, "enableViewRecycling");
|
||||
markFlagAsAccessed(42, "enableViewRecycling");
|
||||
|
||||
flagValue = currentProvider_->enableViewRecycling();
|
||||
enableViewRecycling_ = flagValue;
|
||||
@@ -794,7 +812,7 @@ bool ReactNativeFeatureFlagsAccessor::enableViewRecyclingForImage() {
|
||||
// be accessing the provider multiple times but the end state of this
|
||||
// instance and the returned flag value would be the same.
|
||||
|
||||
markFlagAsAccessed(42, "enableViewRecyclingForImage");
|
||||
markFlagAsAccessed(43, "enableViewRecyclingForImage");
|
||||
|
||||
flagValue = currentProvider_->enableViewRecyclingForImage();
|
||||
enableViewRecyclingForImage_ = flagValue;
|
||||
@@ -812,7 +830,7 @@ bool ReactNativeFeatureFlagsAccessor::enableViewRecyclingForScrollView() {
|
||||
// be accessing the provider multiple times but the end state of this
|
||||
// instance and the returned flag value would be the same.
|
||||
|
||||
markFlagAsAccessed(43, "enableViewRecyclingForScrollView");
|
||||
markFlagAsAccessed(44, "enableViewRecyclingForScrollView");
|
||||
|
||||
flagValue = currentProvider_->enableViewRecyclingForScrollView();
|
||||
enableViewRecyclingForScrollView_ = flagValue;
|
||||
@@ -830,7 +848,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(44, "enableViewRecyclingForText");
|
||||
markFlagAsAccessed(45, "enableViewRecyclingForText");
|
||||
|
||||
flagValue = currentProvider_->enableViewRecyclingForText();
|
||||
enableViewRecyclingForText_ = flagValue;
|
||||
@@ -848,7 +866,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(45, "enableViewRecyclingForView");
|
||||
markFlagAsAccessed(46, "enableViewRecyclingForView");
|
||||
|
||||
flagValue = currentProvider_->enableViewRecyclingForView();
|
||||
enableViewRecyclingForView_ = flagValue;
|
||||
@@ -857,6 +875,24 @@ bool ReactNativeFeatureFlagsAccessor::enableViewRecyclingForView() {
|
||||
return flagValue.value();
|
||||
}
|
||||
|
||||
bool ReactNativeFeatureFlagsAccessor::enableVirtualViewClippingWithoutScrollViewClipping() {
|
||||
auto flagValue = enableVirtualViewClippingWithoutScrollViewClipping_.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(47, "enableVirtualViewClippingWithoutScrollViewClipping");
|
||||
|
||||
flagValue = currentProvider_->enableVirtualViewClippingWithoutScrollViewClipping();
|
||||
enableVirtualViewClippingWithoutScrollViewClipping_ = flagValue;
|
||||
}
|
||||
|
||||
return flagValue.value();
|
||||
}
|
||||
|
||||
bool ReactNativeFeatureFlagsAccessor::enableVirtualViewContainerStateExperimental() {
|
||||
auto flagValue = enableVirtualViewContainerStateExperimental_.load();
|
||||
|
||||
@@ -866,7 +902,7 @@ bool ReactNativeFeatureFlagsAccessor::enableVirtualViewContainerStateExperimenta
|
||||
// be accessing the provider multiple times but the end state of this
|
||||
// instance and the returned flag value would be the same.
|
||||
|
||||
markFlagAsAccessed(46, "enableVirtualViewContainerStateExperimental");
|
||||
markFlagAsAccessed(48, "enableVirtualViewContainerStateExperimental");
|
||||
|
||||
flagValue = currentProvider_->enableVirtualViewContainerStateExperimental();
|
||||
enableVirtualViewContainerStateExperimental_ = flagValue;
|
||||
@@ -884,7 +920,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(47, "enableVirtualViewDebugFeatures");
|
||||
markFlagAsAccessed(49, "enableVirtualViewDebugFeatures");
|
||||
|
||||
flagValue = currentProvider_->enableVirtualViewDebugFeatures();
|
||||
enableVirtualViewDebugFeatures_ = flagValue;
|
||||
@@ -902,7 +938,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(48, "enableVirtualViewRenderState");
|
||||
markFlagAsAccessed(50, "enableVirtualViewRenderState");
|
||||
|
||||
flagValue = currentProvider_->enableVirtualViewRenderState();
|
||||
enableVirtualViewRenderState_ = flagValue;
|
||||
@@ -920,7 +956,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(49, "enableVirtualViewWindowFocusDetection");
|
||||
markFlagAsAccessed(51, "enableVirtualViewWindowFocusDetection");
|
||||
|
||||
flagValue = currentProvider_->enableVirtualViewWindowFocusDetection();
|
||||
enableVirtualViewWindowFocusDetection_ = flagValue;
|
||||
@@ -938,7 +974,7 @@ bool ReactNativeFeatureFlagsAccessor::enableWebPerformanceAPIsByDefault() {
|
||||
// be accessing the provider multiple times but the end state of this
|
||||
// instance and the returned flag value would be the same.
|
||||
|
||||
markFlagAsAccessed(50, "enableWebPerformanceAPIsByDefault");
|
||||
markFlagAsAccessed(52, "enableWebPerformanceAPIsByDefault");
|
||||
|
||||
flagValue = currentProvider_->enableWebPerformanceAPIsByDefault();
|
||||
enableWebPerformanceAPIsByDefault_ = flagValue;
|
||||
@@ -956,7 +992,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(51, "fixMappingOfEventPrioritiesBetweenFabricAndReact");
|
||||
markFlagAsAccessed(53, "fixMappingOfEventPrioritiesBetweenFabricAndReact");
|
||||
|
||||
flagValue = currentProvider_->fixMappingOfEventPrioritiesBetweenFabricAndReact();
|
||||
fixMappingOfEventPrioritiesBetweenFabricAndReact_ = flagValue;
|
||||
@@ -974,7 +1010,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(52, "fuseboxEnabledRelease");
|
||||
markFlagAsAccessed(54, "fuseboxEnabledRelease");
|
||||
|
||||
flagValue = currentProvider_->fuseboxEnabledRelease();
|
||||
fuseboxEnabledRelease_ = flagValue;
|
||||
@@ -992,7 +1028,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(53, "fuseboxNetworkInspectionEnabled");
|
||||
markFlagAsAccessed(55, "fuseboxNetworkInspectionEnabled");
|
||||
|
||||
flagValue = currentProvider_->fuseboxNetworkInspectionEnabled();
|
||||
fuseboxNetworkInspectionEnabled_ = flagValue;
|
||||
@@ -1010,7 +1046,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(54, "hideOffscreenVirtualViewsOnIOS");
|
||||
markFlagAsAccessed(56, "hideOffscreenVirtualViewsOnIOS");
|
||||
|
||||
flagValue = currentProvider_->hideOffscreenVirtualViewsOnIOS();
|
||||
hideOffscreenVirtualViewsOnIOS_ = flagValue;
|
||||
@@ -1028,7 +1064,7 @@ bool ReactNativeFeatureFlagsAccessor::overrideBySynchronousMountPropsAtMountingA
|
||||
// be accessing the provider multiple times but the end state of this
|
||||
// instance and the returned flag value would be the same.
|
||||
|
||||
markFlagAsAccessed(55, "overrideBySynchronousMountPropsAtMountingAndroid");
|
||||
markFlagAsAccessed(57, "overrideBySynchronousMountPropsAtMountingAndroid");
|
||||
|
||||
flagValue = currentProvider_->overrideBySynchronousMountPropsAtMountingAndroid();
|
||||
overrideBySynchronousMountPropsAtMountingAndroid_ = flagValue;
|
||||
@@ -1037,6 +1073,24 @@ bool ReactNativeFeatureFlagsAccessor::overrideBySynchronousMountPropsAtMountingA
|
||||
return flagValue.value();
|
||||
}
|
||||
|
||||
bool ReactNativeFeatureFlagsAccessor::perfIssuesEnabled() {
|
||||
auto flagValue = perfIssuesEnabled_.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(58, "perfIssuesEnabled");
|
||||
|
||||
flagValue = currentProvider_->perfIssuesEnabled();
|
||||
perfIssuesEnabled_ = flagValue;
|
||||
}
|
||||
|
||||
return flagValue.value();
|
||||
}
|
||||
|
||||
bool ReactNativeFeatureFlagsAccessor::perfMonitorV2Enabled() {
|
||||
auto flagValue = perfMonitorV2Enabled_.load();
|
||||
|
||||
@@ -1046,7 +1100,7 @@ bool ReactNativeFeatureFlagsAccessor::perfMonitorV2Enabled() {
|
||||
// be accessing the provider multiple times but the end state of this
|
||||
// instance and the returned flag value would be the same.
|
||||
|
||||
markFlagAsAccessed(56, "perfMonitorV2Enabled");
|
||||
markFlagAsAccessed(59, "perfMonitorV2Enabled");
|
||||
|
||||
flagValue = currentProvider_->perfMonitorV2Enabled();
|
||||
perfMonitorV2Enabled_ = flagValue;
|
||||
@@ -1064,7 +1118,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(57, "preparedTextCacheSize");
|
||||
markFlagAsAccessed(60, "preparedTextCacheSize");
|
||||
|
||||
flagValue = currentProvider_->preparedTextCacheSize();
|
||||
preparedTextCacheSize_ = flagValue;
|
||||
@@ -1082,7 +1136,7 @@ bool ReactNativeFeatureFlagsAccessor::preventShadowTreeCommitExhaustion() {
|
||||
// be accessing the provider multiple times but the end state of this
|
||||
// instance and the returned flag value would be the same.
|
||||
|
||||
markFlagAsAccessed(58, "preventShadowTreeCommitExhaustion");
|
||||
markFlagAsAccessed(61, "preventShadowTreeCommitExhaustion");
|
||||
|
||||
flagValue = currentProvider_->preventShadowTreeCommitExhaustion();
|
||||
preventShadowTreeCommitExhaustion_ = flagValue;
|
||||
@@ -1100,7 +1154,7 @@ bool ReactNativeFeatureFlagsAccessor::shouldPressibilityUseW3CPointerEventsForHo
|
||||
// be accessing the provider multiple times but the end state of this
|
||||
// instance and the returned flag value would be the same.
|
||||
|
||||
markFlagAsAccessed(59, "shouldPressibilityUseW3CPointerEventsForHover");
|
||||
markFlagAsAccessed(62, "shouldPressibilityUseW3CPointerEventsForHover");
|
||||
|
||||
flagValue = currentProvider_->shouldPressibilityUseW3CPointerEventsForHover();
|
||||
shouldPressibilityUseW3CPointerEventsForHover_ = flagValue;
|
||||
@@ -1118,7 +1172,7 @@ bool ReactNativeFeatureFlagsAccessor::shouldTriggerResponderTransferOnScrollAndr
|
||||
// be accessing the provider multiple times but the end state of this
|
||||
// instance and the returned flag value would be the same.
|
||||
|
||||
markFlagAsAccessed(60, "shouldTriggerResponderTransferOnScrollAndroid");
|
||||
markFlagAsAccessed(63, "shouldTriggerResponderTransferOnScrollAndroid");
|
||||
|
||||
flagValue = currentProvider_->shouldTriggerResponderTransferOnScrollAndroid();
|
||||
shouldTriggerResponderTransferOnScrollAndroid_ = flagValue;
|
||||
@@ -1136,7 +1190,7 @@ bool ReactNativeFeatureFlagsAccessor::skipActivityIdentityAssertionOnHostPause()
|
||||
// be accessing the provider multiple times but the end state of this
|
||||
// instance and the returned flag value would be the same.
|
||||
|
||||
markFlagAsAccessed(61, "skipActivityIdentityAssertionOnHostPause");
|
||||
markFlagAsAccessed(64, "skipActivityIdentityAssertionOnHostPause");
|
||||
|
||||
flagValue = currentProvider_->skipActivityIdentityAssertionOnHostPause();
|
||||
skipActivityIdentityAssertionOnHostPause_ = flagValue;
|
||||
@@ -1154,7 +1208,7 @@ bool ReactNativeFeatureFlagsAccessor::sweepActiveTouchOnChildNativeGesturesAndro
|
||||
// be accessing the provider multiple times but the end state of this
|
||||
// instance and the returned flag value would be the same.
|
||||
|
||||
markFlagAsAccessed(62, "sweepActiveTouchOnChildNativeGesturesAndroid");
|
||||
markFlagAsAccessed(65, "sweepActiveTouchOnChildNativeGesturesAndroid");
|
||||
|
||||
flagValue = currentProvider_->sweepActiveTouchOnChildNativeGesturesAndroid();
|
||||
sweepActiveTouchOnChildNativeGesturesAndroid_ = flagValue;
|
||||
@@ -1172,7 +1226,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(63, "traceTurboModulePromiseRejectionsOnAndroid");
|
||||
markFlagAsAccessed(66, "traceTurboModulePromiseRejectionsOnAndroid");
|
||||
|
||||
flagValue = currentProvider_->traceTurboModulePromiseRejectionsOnAndroid();
|
||||
traceTurboModulePromiseRejectionsOnAndroid_ = flagValue;
|
||||
@@ -1190,7 +1244,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(64, "updateRuntimeShadowNodeReferencesOnCommit");
|
||||
markFlagAsAccessed(67, "updateRuntimeShadowNodeReferencesOnCommit");
|
||||
|
||||
flagValue = currentProvider_->updateRuntimeShadowNodeReferencesOnCommit();
|
||||
updateRuntimeShadowNodeReferencesOnCommit_ = flagValue;
|
||||
@@ -1208,7 +1262,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(65, "useAlwaysAvailableJSErrorHandling");
|
||||
markFlagAsAccessed(68, "useAlwaysAvailableJSErrorHandling");
|
||||
|
||||
flagValue = currentProvider_->useAlwaysAvailableJSErrorHandling();
|
||||
useAlwaysAvailableJSErrorHandling_ = flagValue;
|
||||
@@ -1226,7 +1280,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(66, "useFabricInterop");
|
||||
markFlagAsAccessed(69, "useFabricInterop");
|
||||
|
||||
flagValue = currentProvider_->useFabricInterop();
|
||||
useFabricInterop_ = flagValue;
|
||||
@@ -1244,7 +1298,7 @@ bool ReactNativeFeatureFlagsAccessor::useNativeEqualsInNativeReadableArrayAndroi
|
||||
// be accessing the provider multiple times but the end state of this
|
||||
// instance and the returned flag value would be the same.
|
||||
|
||||
markFlagAsAccessed(67, "useNativeEqualsInNativeReadableArrayAndroid");
|
||||
markFlagAsAccessed(70, "useNativeEqualsInNativeReadableArrayAndroid");
|
||||
|
||||
flagValue = currentProvider_->useNativeEqualsInNativeReadableArrayAndroid();
|
||||
useNativeEqualsInNativeReadableArrayAndroid_ = flagValue;
|
||||
@@ -1262,7 +1316,7 @@ bool ReactNativeFeatureFlagsAccessor::useNativeTransformHelperAndroid() {
|
||||
// be accessing the provider multiple times but the end state of this
|
||||
// instance and the returned flag value would be the same.
|
||||
|
||||
markFlagAsAccessed(68, "useNativeTransformHelperAndroid");
|
||||
markFlagAsAccessed(71, "useNativeTransformHelperAndroid");
|
||||
|
||||
flagValue = currentProvider_->useNativeTransformHelperAndroid();
|
||||
useNativeTransformHelperAndroid_ = flagValue;
|
||||
@@ -1280,7 +1334,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(69, "useNativeViewConfigsInBridgelessMode");
|
||||
markFlagAsAccessed(72, "useNativeViewConfigsInBridgelessMode");
|
||||
|
||||
flagValue = currentProvider_->useNativeViewConfigsInBridgelessMode();
|
||||
useNativeViewConfigsInBridgelessMode_ = flagValue;
|
||||
@@ -1298,7 +1352,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(70, "useOptimizedEventBatchingOnAndroid");
|
||||
markFlagAsAccessed(73, "useOptimizedEventBatchingOnAndroid");
|
||||
|
||||
flagValue = currentProvider_->useOptimizedEventBatchingOnAndroid();
|
||||
useOptimizedEventBatchingOnAndroid_ = flagValue;
|
||||
@@ -1316,7 +1370,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(71, "useRawPropsJsiValue");
|
||||
markFlagAsAccessed(74, "useRawPropsJsiValue");
|
||||
|
||||
flagValue = currentProvider_->useRawPropsJsiValue();
|
||||
useRawPropsJsiValue_ = flagValue;
|
||||
@@ -1334,7 +1388,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(72, "useShadowNodeStateOnClone");
|
||||
markFlagAsAccessed(75, "useShadowNodeStateOnClone");
|
||||
|
||||
flagValue = currentProvider_->useShadowNodeStateOnClone();
|
||||
useShadowNodeStateOnClone_ = flagValue;
|
||||
@@ -1352,7 +1406,7 @@ bool ReactNativeFeatureFlagsAccessor::useSharedAnimatedBackend() {
|
||||
// be accessing the provider multiple times but the end state of this
|
||||
// instance and the returned flag value would be the same.
|
||||
|
||||
markFlagAsAccessed(73, "useSharedAnimatedBackend");
|
||||
markFlagAsAccessed(76, "useSharedAnimatedBackend");
|
||||
|
||||
flagValue = currentProvider_->useSharedAnimatedBackend();
|
||||
useSharedAnimatedBackend_ = flagValue;
|
||||
@@ -1370,7 +1424,7 @@ bool ReactNativeFeatureFlagsAccessor::useTraitHiddenOnAndroid() {
|
||||
// be accessing the provider multiple times but the end state of this
|
||||
// instance and the returned flag value would be the same.
|
||||
|
||||
markFlagAsAccessed(74, "useTraitHiddenOnAndroid");
|
||||
markFlagAsAccessed(77, "useTraitHiddenOnAndroid");
|
||||
|
||||
flagValue = currentProvider_->useTraitHiddenOnAndroid();
|
||||
useTraitHiddenOnAndroid_ = flagValue;
|
||||
@@ -1388,7 +1442,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(75, "useTurboModuleInterop");
|
||||
markFlagAsAccessed(78, "useTurboModuleInterop");
|
||||
|
||||
flagValue = currentProvider_->useTurboModuleInterop();
|
||||
useTurboModuleInterop_ = flagValue;
|
||||
@@ -1406,7 +1460,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(76, "useTurboModules");
|
||||
markFlagAsAccessed(79, "useTurboModules");
|
||||
|
||||
flagValue = currentProvider_->useTurboModules();
|
||||
useTurboModules_ = flagValue;
|
||||
@@ -1424,7 +1478,7 @@ double ReactNativeFeatureFlagsAccessor::viewCullingOutsetRatio() {
|
||||
// be accessing the provider multiple times but the end state of this
|
||||
// instance and the returned flag value would be the same.
|
||||
|
||||
markFlagAsAccessed(77, "viewCullingOutsetRatio");
|
||||
markFlagAsAccessed(80, "viewCullingOutsetRatio");
|
||||
|
||||
flagValue = currentProvider_->viewCullingOutsetRatio();
|
||||
viewCullingOutsetRatio_ = flagValue;
|
||||
@@ -1442,7 +1496,7 @@ double ReactNativeFeatureFlagsAccessor::virtualViewHysteresisRatio() {
|
||||
// be accessing the provider multiple times but the end state of this
|
||||
// instance and the returned flag value would be the same.
|
||||
|
||||
markFlagAsAccessed(78, "virtualViewHysteresisRatio");
|
||||
markFlagAsAccessed(81, "virtualViewHysteresisRatio");
|
||||
|
||||
flagValue = currentProvider_->virtualViewHysteresisRatio();
|
||||
virtualViewHysteresisRatio_ = flagValue;
|
||||
@@ -1460,7 +1514,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(79, "virtualViewPrerenderRatio");
|
||||
markFlagAsAccessed(82, "virtualViewPrerenderRatio");
|
||||
|
||||
flagValue = currentProvider_->virtualViewPrerenderRatio();
|
||||
virtualViewPrerenderRatio_ = flagValue;
|
||||
|
||||
+8
-2
@@ -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<<de758de45c903f7bf895bf03e049a20a>>
|
||||
* @generated SignedSource<<e7e8d311c0d1cca4e28bee7ddcf5065c>>
|
||||
*/
|
||||
|
||||
/**
|
||||
@@ -62,6 +62,7 @@ class ReactNativeFeatureFlagsAccessor {
|
||||
bool enableImmediateUpdateModeForContentOffsetChanges();
|
||||
bool enableImperativeFocus();
|
||||
bool enableInteropViewManagerClassLookUpOptimizationIOS();
|
||||
bool enableKeyEvents();
|
||||
bool enableLayoutAnimationsOnAndroid();
|
||||
bool enableLayoutAnimationsOnIOS();
|
||||
bool enableMainQueueCoordinatorOnIOS();
|
||||
@@ -78,6 +79,7 @@ class ReactNativeFeatureFlagsAccessor {
|
||||
bool enableViewRecyclingForScrollView();
|
||||
bool enableViewRecyclingForText();
|
||||
bool enableViewRecyclingForView();
|
||||
bool enableVirtualViewClippingWithoutScrollViewClipping();
|
||||
bool enableVirtualViewContainerStateExperimental();
|
||||
bool enableVirtualViewDebugFeatures();
|
||||
bool enableVirtualViewRenderState();
|
||||
@@ -88,6 +90,7 @@ class ReactNativeFeatureFlagsAccessor {
|
||||
bool fuseboxNetworkInspectionEnabled();
|
||||
bool hideOffscreenVirtualViewsOnIOS();
|
||||
bool overrideBySynchronousMountPropsAtMountingAndroid();
|
||||
bool perfIssuesEnabled();
|
||||
bool perfMonitorV2Enabled();
|
||||
double preparedTextCacheSize();
|
||||
bool preventShadowTreeCommitExhaustion();
|
||||
@@ -123,7 +126,7 @@ class ReactNativeFeatureFlagsAccessor {
|
||||
std::unique_ptr<ReactNativeFeatureFlagsProvider> currentProvider_;
|
||||
bool wasOverridden_;
|
||||
|
||||
std::array<std::atomic<const char*>, 80> accessedFeatureFlags_;
|
||||
std::array<std::atomic<const char*>, 83> accessedFeatureFlags_;
|
||||
|
||||
std::atomic<std::optional<bool>> commonTestFlag_;
|
||||
std::atomic<std::optional<bool>> cdpInteractionMetricsEnabled_;
|
||||
@@ -155,6 +158,7 @@ class ReactNativeFeatureFlagsAccessor {
|
||||
std::atomic<std::optional<bool>> enableImmediateUpdateModeForContentOffsetChanges_;
|
||||
std::atomic<std::optional<bool>> enableImperativeFocus_;
|
||||
std::atomic<std::optional<bool>> enableInteropViewManagerClassLookUpOptimizationIOS_;
|
||||
std::atomic<std::optional<bool>> enableKeyEvents_;
|
||||
std::atomic<std::optional<bool>> enableLayoutAnimationsOnAndroid_;
|
||||
std::atomic<std::optional<bool>> enableLayoutAnimationsOnIOS_;
|
||||
std::atomic<std::optional<bool>> enableMainQueueCoordinatorOnIOS_;
|
||||
@@ -171,6 +175,7 @@ class ReactNativeFeatureFlagsAccessor {
|
||||
std::atomic<std::optional<bool>> enableViewRecyclingForScrollView_;
|
||||
std::atomic<std::optional<bool>> enableViewRecyclingForText_;
|
||||
std::atomic<std::optional<bool>> enableViewRecyclingForView_;
|
||||
std::atomic<std::optional<bool>> enableVirtualViewClippingWithoutScrollViewClipping_;
|
||||
std::atomic<std::optional<bool>> enableVirtualViewContainerStateExperimental_;
|
||||
std::atomic<std::optional<bool>> enableVirtualViewDebugFeatures_;
|
||||
std::atomic<std::optional<bool>> enableVirtualViewRenderState_;
|
||||
@@ -181,6 +186,7 @@ class ReactNativeFeatureFlagsAccessor {
|
||||
std::atomic<std::optional<bool>> fuseboxNetworkInspectionEnabled_;
|
||||
std::atomic<std::optional<bool>> hideOffscreenVirtualViewsOnIOS_;
|
||||
std::atomic<std::optional<bool>> overrideBySynchronousMountPropsAtMountingAndroid_;
|
||||
std::atomic<std::optional<bool>> perfIssuesEnabled_;
|
||||
std::atomic<std::optional<bool>> perfMonitorV2Enabled_;
|
||||
std::atomic<std::optional<double>> preparedTextCacheSize_;
|
||||
std::atomic<std::optional<bool>> preventShadowTreeCommitExhaustion_;
|
||||
|
||||
+15
-3
@@ -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<<21049b33fc72200390c6dd6d0ca27c19>>
|
||||
* @generated SignedSource<<a0a1898f3a4c14179bd03d5dbe97adfa>>
|
||||
*/
|
||||
|
||||
/**
|
||||
@@ -147,6 +147,10 @@ class ReactNativeFeatureFlagsDefaults : public ReactNativeFeatureFlagsProvider {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool enableKeyEvents() override {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool enableLayoutAnimationsOnAndroid() override {
|
||||
return false;
|
||||
}
|
||||
@@ -211,6 +215,10 @@ class ReactNativeFeatureFlagsDefaults : public ReactNativeFeatureFlagsProvider {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool enableVirtualViewClippingWithoutScrollViewClipping() override {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool enableVirtualViewContainerStateExperimental() override {
|
||||
return false;
|
||||
}
|
||||
@@ -228,7 +236,7 @@ class ReactNativeFeatureFlagsDefaults : public ReactNativeFeatureFlagsProvider {
|
||||
}
|
||||
|
||||
bool enableWebPerformanceAPIsByDefault() override {
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool fixMappingOfEventPrioritiesBetweenFabricAndReact() override {
|
||||
@@ -251,6 +259,10 @@ class ReactNativeFeatureFlagsDefaults : public ReactNativeFeatureFlagsProvider {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool perfIssuesEnabled() override {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool perfMonitorV2Enabled() override {
|
||||
return false;
|
||||
}
|
||||
@@ -276,7 +288,7 @@ class ReactNativeFeatureFlagsDefaults : public ReactNativeFeatureFlagsProvider {
|
||||
}
|
||||
|
||||
bool sweepActiveTouchOnChildNativeGesturesAndroid() override {
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool traceTurboModulePromiseRejectionsOnAndroid() override {
|
||||
|
||||
+28
-1
@@ -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<<cc71bfa62258ec91b00c4646441fa7fc>>
|
||||
* @generated SignedSource<<fc8f8541827a039fa5bc4a113e75fdf6>>
|
||||
*/
|
||||
|
||||
/**
|
||||
@@ -315,6 +315,15 @@ class ReactNativeFeatureFlagsDynamicProvider : public ReactNativeFeatureFlagsDef
|
||||
return ReactNativeFeatureFlagsDefaults::enableInteropViewManagerClassLookUpOptimizationIOS();
|
||||
}
|
||||
|
||||
bool enableKeyEvents() override {
|
||||
auto value = values_["enableKeyEvents"];
|
||||
if (!value.isNull()) {
|
||||
return value.getBool();
|
||||
}
|
||||
|
||||
return ReactNativeFeatureFlagsDefaults::enableKeyEvents();
|
||||
}
|
||||
|
||||
bool enableLayoutAnimationsOnAndroid() override {
|
||||
auto value = values_["enableLayoutAnimationsOnAndroid"];
|
||||
if (!value.isNull()) {
|
||||
@@ -459,6 +468,15 @@ class ReactNativeFeatureFlagsDynamicProvider : public ReactNativeFeatureFlagsDef
|
||||
return ReactNativeFeatureFlagsDefaults::enableViewRecyclingForView();
|
||||
}
|
||||
|
||||
bool enableVirtualViewClippingWithoutScrollViewClipping() override {
|
||||
auto value = values_["enableVirtualViewClippingWithoutScrollViewClipping"];
|
||||
if (!value.isNull()) {
|
||||
return value.getBool();
|
||||
}
|
||||
|
||||
return ReactNativeFeatureFlagsDefaults::enableVirtualViewClippingWithoutScrollViewClipping();
|
||||
}
|
||||
|
||||
bool enableVirtualViewContainerStateExperimental() override {
|
||||
auto value = values_["enableVirtualViewContainerStateExperimental"];
|
||||
if (!value.isNull()) {
|
||||
@@ -549,6 +567,15 @@ class ReactNativeFeatureFlagsDynamicProvider : public ReactNativeFeatureFlagsDef
|
||||
return ReactNativeFeatureFlagsDefaults::overrideBySynchronousMountPropsAtMountingAndroid();
|
||||
}
|
||||
|
||||
bool perfIssuesEnabled() override {
|
||||
auto value = values_["perfIssuesEnabled"];
|
||||
if (!value.isNull()) {
|
||||
return value.getBool();
|
||||
}
|
||||
|
||||
return ReactNativeFeatureFlagsDefaults::perfIssuesEnabled();
|
||||
}
|
||||
|
||||
bool perfMonitorV2Enabled() override {
|
||||
auto value = values_["perfMonitorV2Enabled"];
|
||||
if (!value.isNull()) {
|
||||
|
||||
+1
-5
@@ -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<<32a03e199994c91c022013d7929bfea5>>
|
||||
* @generated SignedSource<<db8626cf78a3ed226bbbe6bf20cc03a2>>
|
||||
*/
|
||||
|
||||
/**
|
||||
@@ -35,10 +35,6 @@ class ReactNativeFeatureFlagsOverridesOSSCanary : public ReactNativeFeatureFlags
|
||||
return true;
|
||||
}
|
||||
|
||||
bool enableWebPerformanceAPIsByDefault() override {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool useNativeViewConfigsInBridgelessMode() override {
|
||||
return true;
|
||||
}
|
||||
|
||||
+4
-1
@@ -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<<4b639e1b0211b16826bcfd1a19dd6658>>
|
||||
* @generated SignedSource<<5dcaab263795b1605da54dbbb617264f>>
|
||||
*/
|
||||
|
||||
/**
|
||||
@@ -55,6 +55,7 @@ class ReactNativeFeatureFlagsProvider {
|
||||
virtual bool enableImmediateUpdateModeForContentOffsetChanges() = 0;
|
||||
virtual bool enableImperativeFocus() = 0;
|
||||
virtual bool enableInteropViewManagerClassLookUpOptimizationIOS() = 0;
|
||||
virtual bool enableKeyEvents() = 0;
|
||||
virtual bool enableLayoutAnimationsOnAndroid() = 0;
|
||||
virtual bool enableLayoutAnimationsOnIOS() = 0;
|
||||
virtual bool enableMainQueueCoordinatorOnIOS() = 0;
|
||||
@@ -71,6 +72,7 @@ class ReactNativeFeatureFlagsProvider {
|
||||
virtual bool enableViewRecyclingForScrollView() = 0;
|
||||
virtual bool enableViewRecyclingForText() = 0;
|
||||
virtual bool enableViewRecyclingForView() = 0;
|
||||
virtual bool enableVirtualViewClippingWithoutScrollViewClipping() = 0;
|
||||
virtual bool enableVirtualViewContainerStateExperimental() = 0;
|
||||
virtual bool enableVirtualViewDebugFeatures() = 0;
|
||||
virtual bool enableVirtualViewRenderState() = 0;
|
||||
@@ -81,6 +83,7 @@ class ReactNativeFeatureFlagsProvider {
|
||||
virtual bool fuseboxNetworkInspectionEnabled() = 0;
|
||||
virtual bool hideOffscreenVirtualViewsOnIOS() = 0;
|
||||
virtual bool overrideBySynchronousMountPropsAtMountingAndroid() = 0;
|
||||
virtual bool perfIssuesEnabled() = 0;
|
||||
virtual bool perfMonitorV2Enabled() = 0;
|
||||
virtual double preparedTextCacheSize() = 0;
|
||||
virtual bool preventShadowTreeCommitExhaustion() = 0;
|
||||
|
||||
+16
-1
@@ -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<<81b1cc08f5f6aa5f44c002eb7992811f>>
|
||||
* @generated SignedSource<<6bd64914d0e2f0c727490a420496fbb0>>
|
||||
*/
|
||||
|
||||
/**
|
||||
@@ -194,6 +194,11 @@ bool NativeReactNativeFeatureFlags::enableInteropViewManagerClassLookUpOptimizat
|
||||
return ReactNativeFeatureFlags::enableInteropViewManagerClassLookUpOptimizationIOS();
|
||||
}
|
||||
|
||||
bool NativeReactNativeFeatureFlags::enableKeyEvents(
|
||||
jsi::Runtime& /*runtime*/) {
|
||||
return ReactNativeFeatureFlags::enableKeyEvents();
|
||||
}
|
||||
|
||||
bool NativeReactNativeFeatureFlags::enableLayoutAnimationsOnAndroid(
|
||||
jsi::Runtime& /*runtime*/) {
|
||||
return ReactNativeFeatureFlags::enableLayoutAnimationsOnAndroid();
|
||||
@@ -274,6 +279,11 @@ bool NativeReactNativeFeatureFlags::enableViewRecyclingForView(
|
||||
return ReactNativeFeatureFlags::enableViewRecyclingForView();
|
||||
}
|
||||
|
||||
bool NativeReactNativeFeatureFlags::enableVirtualViewClippingWithoutScrollViewClipping(
|
||||
jsi::Runtime& /*runtime*/) {
|
||||
return ReactNativeFeatureFlags::enableVirtualViewClippingWithoutScrollViewClipping();
|
||||
}
|
||||
|
||||
bool NativeReactNativeFeatureFlags::enableVirtualViewContainerStateExperimental(
|
||||
jsi::Runtime& /*runtime*/) {
|
||||
return ReactNativeFeatureFlags::enableVirtualViewContainerStateExperimental();
|
||||
@@ -324,6 +334,11 @@ bool NativeReactNativeFeatureFlags::overrideBySynchronousMountPropsAtMountingAnd
|
||||
return ReactNativeFeatureFlags::overrideBySynchronousMountPropsAtMountingAndroid();
|
||||
}
|
||||
|
||||
bool NativeReactNativeFeatureFlags::perfIssuesEnabled(
|
||||
jsi::Runtime& /*runtime*/) {
|
||||
return ReactNativeFeatureFlags::perfIssuesEnabled();
|
||||
}
|
||||
|
||||
bool NativeReactNativeFeatureFlags::perfMonitorV2Enabled(
|
||||
jsi::Runtime& /*runtime*/) {
|
||||
return ReactNativeFeatureFlags::perfMonitorV2Enabled();
|
||||
|
||||
+7
-1
@@ -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<<2ac15ead28cac3a969854f339d625dca>>
|
||||
* @generated SignedSource<<99624bd7682ad34476ac395e8acc43c7>>
|
||||
*/
|
||||
|
||||
/**
|
||||
@@ -96,6 +96,8 @@ class NativeReactNativeFeatureFlags
|
||||
|
||||
bool enableInteropViewManagerClassLookUpOptimizationIOS(jsi::Runtime& runtime);
|
||||
|
||||
bool enableKeyEvents(jsi::Runtime& runtime);
|
||||
|
||||
bool enableLayoutAnimationsOnAndroid(jsi::Runtime& runtime);
|
||||
|
||||
bool enableLayoutAnimationsOnIOS(jsi::Runtime& runtime);
|
||||
@@ -128,6 +130,8 @@ class NativeReactNativeFeatureFlags
|
||||
|
||||
bool enableViewRecyclingForView(jsi::Runtime& runtime);
|
||||
|
||||
bool enableVirtualViewClippingWithoutScrollViewClipping(jsi::Runtime& runtime);
|
||||
|
||||
bool enableVirtualViewContainerStateExperimental(jsi::Runtime& runtime);
|
||||
|
||||
bool enableVirtualViewDebugFeatures(jsi::Runtime& runtime);
|
||||
@@ -148,6 +152,8 @@ class NativeReactNativeFeatureFlags
|
||||
|
||||
bool overrideBySynchronousMountPropsAtMountingAndroid(jsi::Runtime& runtime);
|
||||
|
||||
bool perfIssuesEnabled(jsi::Runtime& runtime);
|
||||
|
||||
bool perfMonitorV2Enabled(jsi::Runtime& runtime);
|
||||
|
||||
double preparedTextCacheSize(jsi::Runtime& runtime);
|
||||
|
||||
@@ -19,11 +19,11 @@ namespace facebook::react {
|
||||
* [Experimental] Reports CDP interaction events via the
|
||||
* "__chromium_devtools_metrics_reporter" runtime binding.
|
||||
*
|
||||
* This populates the Interaction to Next Paint (INP) live metric in Chrome
|
||||
* DevTools and the V2 Perf Monitor. Events are reported immediately and do
|
||||
* not require an active CDP Tracing session.
|
||||
* This populates the Interaction to Next Paint (INP) live metric in React
|
||||
* Native DevTools. Events are reported immediately and do not require an
|
||||
* active CDP Tracing session.
|
||||
*/
|
||||
class CdpMetricsReporter : public PerformanceEntryReporterEventTimingListener {
|
||||
class CdpMetricsReporter : public PerformanceEntryReporterEventListener {
|
||||
public:
|
||||
explicit CdpMetricsReporter(RuntimeExecutor runtimeExecutor);
|
||||
|
||||
|
||||
+60
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* 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 "CdpPerfIssuesReporter.h"
|
||||
|
||||
#include <folly/dynamic.h>
|
||||
#include <folly/json.h>
|
||||
#include <string_view>
|
||||
|
||||
namespace facebook::react {
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr std::string_view issuesReporterName =
|
||||
"__react_native_perf_issues_reporter";
|
||||
|
||||
} // namespace
|
||||
|
||||
CdpPerfIssuesReporter::CdpPerfIssuesReporter(RuntimeExecutor runtimeExecutor)
|
||||
: runtimeExecutor_(std::move(runtimeExecutor)) {}
|
||||
|
||||
void CdpPerfIssuesReporter::onMeasureEntry(
|
||||
const PerformanceMeasure& entry,
|
||||
const std::optional<UserTimingDetailProvider>& detailProvider) {
|
||||
std::optional<folly::dynamic> maybeDetail = nullptr;
|
||||
if (detailProvider.has_value()) {
|
||||
maybeDetail = (*detailProvider)();
|
||||
}
|
||||
|
||||
if (!maybeDetail.has_value() || !maybeDetail->isObject()) {
|
||||
return;
|
||||
}
|
||||
|
||||
runtimeExecutor_([entry,
|
||||
detail = std::move(*maybeDetail)](jsi::Runtime& runtime) {
|
||||
auto global = runtime.global();
|
||||
if (!global.hasProperty(runtime, issuesReporterName.data())) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (detail.count("rnPerfIssue") != 0 && detail["rnPerfIssue"].isObject()) {
|
||||
auto& perfIssue = detail["rnPerfIssue"];
|
||||
|
||||
if (perfIssue.count("name") != 0 && perfIssue.count("severity") != 0 &&
|
||||
perfIssue.count("description") != 0) {
|
||||
auto jsonString = folly::toJson(perfIssue);
|
||||
auto jsiString = jsi::String::createFromUtf8(runtime, jsonString);
|
||||
auto issuesReporter =
|
||||
global.getPropertyAsFunction(runtime, issuesReporterName.data());
|
||||
issuesReporter.call(runtime, jsiString);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
} // namespace facebook::react
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ReactCommon/RuntimeExecutor.h>
|
||||
#include <folly/dynamic.h>
|
||||
#include <jsi/jsi.h>
|
||||
#include <react/performance/timeline/PerformanceEntry.h>
|
||||
#include <react/performance/timeline/PerformanceEntryReporterListeners.h>
|
||||
#include <react/timing/primitives.h>
|
||||
|
||||
namespace facebook::react {
|
||||
|
||||
/**
|
||||
* [Experimental] Reports new Performance Issues via the
|
||||
* "__react_native_perf_issues_reporter" runtime binding.
|
||||
*
|
||||
* This populates the Perf Issues indicator in the V2 Perf Monitor. Events are
|
||||
* reported immediately and do not require an active CDP Tracing session.
|
||||
*/
|
||||
class CdpPerfIssuesReporter : public PerformanceEntryReporterEventListener {
|
||||
public:
|
||||
explicit CdpPerfIssuesReporter(RuntimeExecutor runtimeExecutor);
|
||||
|
||||
void onMeasureEntry(const PerformanceMeasure &entry, const std::optional<UserTimingDetailProvider> &detailProvider)
|
||||
override;
|
||||
|
||||
private:
|
||||
const RuntimeExecutor runtimeExecutor_{};
|
||||
};
|
||||
|
||||
} // namespace facebook::react
|
||||
+26
-15
@@ -88,19 +88,18 @@ PerformanceEntryReporter::PerformanceEntryReporter()
|
||||
#endif
|
||||
}
|
||||
|
||||
void PerformanceEntryReporter::addEventTimingListener(
|
||||
PerformanceEntryReporterEventTimingListener* listener) {
|
||||
void PerformanceEntryReporter::addEventListener(
|
||||
PerformanceEntryReporterEventListener* listener) {
|
||||
std::unique_lock lock(listenersMutex_);
|
||||
eventTimingListeners_.push_back(listener);
|
||||
eventListeners_.push_back(listener);
|
||||
}
|
||||
|
||||
void PerformanceEntryReporter::removeEventTimingListener(
|
||||
PerformanceEntryReporterEventTimingListener* listener) {
|
||||
void PerformanceEntryReporter::removeEventListener(
|
||||
PerformanceEntryReporterEventListener* listener) {
|
||||
std::unique_lock lock(listenersMutex_);
|
||||
auto it = std::find(
|
||||
eventTimingListeners_.begin(), eventTimingListeners_.end(), listener);
|
||||
if (it != eventTimingListeners_.end()) {
|
||||
eventTimingListeners_.erase(it);
|
||||
auto it = std::find(eventListeners_.begin(), eventListeners_.end(), listener);
|
||||
if (it != eventListeners_.end()) {
|
||||
eventListeners_.erase(it);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -208,13 +207,13 @@ void PerformanceEntryReporter::reportMeasure(
|
||||
const std::string& name,
|
||||
HighResTimeStamp startTime,
|
||||
HighResDuration duration,
|
||||
UserTimingDetailProvider&& detailProvider) {
|
||||
const std::optional<UserTimingDetailProvider>& detailProvider) {
|
||||
const auto entry = PerformanceMeasure{
|
||||
{.name = std::string(name),
|
||||
.startTime = startTime,
|
||||
.duration = duration}};
|
||||
|
||||
traceMeasure(entry, std::move(detailProvider));
|
||||
traceMeasure(entry, detailProvider);
|
||||
|
||||
// Add to buffers & notify observers
|
||||
{
|
||||
@@ -223,6 +222,16 @@ void PerformanceEntryReporter::reportMeasure(
|
||||
}
|
||||
|
||||
observerRegistry_->queuePerformanceEntry(entry);
|
||||
|
||||
std::vector<PerformanceEntryReporterEventListener*> listenersCopy;
|
||||
{
|
||||
std::shared_lock lock(listenersMutex_);
|
||||
listenersCopy = eventListeners_;
|
||||
}
|
||||
|
||||
for (auto* listener : listenersCopy) {
|
||||
listener->onMeasureEntry(entry, detailProvider);
|
||||
}
|
||||
}
|
||||
|
||||
void PerformanceEntryReporter::clearEventCounts() {
|
||||
@@ -272,10 +281,10 @@ void PerformanceEntryReporter::reportEvent(
|
||||
// TODO(T198982346): Log interaction events to jsinspector_modern
|
||||
observerRegistry_->queuePerformanceEntry(entry);
|
||||
|
||||
std::vector<PerformanceEntryReporterEventTimingListener*> listenersCopy;
|
||||
std::vector<PerformanceEntryReporterEventListener*> listenersCopy;
|
||||
{
|
||||
std::shared_lock lock(listenersMutex_);
|
||||
listenersCopy = eventTimingListeners_;
|
||||
listenersCopy = eventListeners_;
|
||||
}
|
||||
|
||||
for (auto* listener : listenersCopy) {
|
||||
@@ -354,11 +363,13 @@ void PerformanceEntryReporter::traceMark(
|
||||
|
||||
void PerformanceEntryReporter::traceMeasure(
|
||||
const PerformanceMeasure& entry,
|
||||
UserTimingDetailProvider&& detailProvider) const {
|
||||
const std::optional<UserTimingDetailProvider>& detailProvider) const {
|
||||
auto& performanceTracer =
|
||||
jsinspector_modern::tracing::PerformanceTracer::getInstance();
|
||||
if (performanceTracer.isTracing() || ReactPerfettoLogger::isTracing()) {
|
||||
auto detail = detailProvider != nullptr ? detailProvider() : nullptr;
|
||||
auto detail = detailProvider && detailProvider.has_value()
|
||||
? (*detailProvider)()
|
||||
: nullptr;
|
||||
|
||||
if (ReactPerfettoLogger::isTracing()) {
|
||||
ReactPerfettoLogger::measure(
|
||||
|
||||
+6
-5
@@ -59,8 +59,8 @@ class PerformanceEntryReporter {
|
||||
void clearEntries(PerformanceEntryType entryType);
|
||||
void clearEntries(PerformanceEntryType entryType, const std::string &entryName);
|
||||
|
||||
void addEventTimingListener(PerformanceEntryReporterEventTimingListener *listener);
|
||||
void removeEventTimingListener(PerformanceEntryReporterEventTimingListener *listener);
|
||||
void addEventListener(PerformanceEntryReporterEventListener *listener);
|
||||
void removeEventListener(PerformanceEntryReporterEventListener *listener);
|
||||
|
||||
static std::vector<PerformanceEntryType> getSupportedEntryTypes();
|
||||
|
||||
@@ -84,7 +84,7 @@ class PerformanceEntryReporter {
|
||||
const std::string &name,
|
||||
HighResTimeStamp startTime,
|
||||
HighResDuration duration,
|
||||
UserTimingDetailProvider &&detailProvider = nullptr);
|
||||
const std::optional<UserTimingDetailProvider> &detailProvider = std::nullopt);
|
||||
|
||||
void reportEvent(
|
||||
const std::string &name,
|
||||
@@ -123,7 +123,7 @@ class PerformanceEntryReporter {
|
||||
std::unordered_map<std::string, uint32_t> eventCounts_;
|
||||
|
||||
mutable std::shared_mutex listenersMutex_;
|
||||
std::vector<PerformanceEntryReporterEventTimingListener *> eventTimingListeners_{};
|
||||
std::vector<PerformanceEntryReporterEventListener *> eventListeners_{};
|
||||
|
||||
const inline PerformanceEntryBuffer &getBuffer(PerformanceEntryType entryType) const
|
||||
{
|
||||
@@ -166,7 +166,8 @@ class PerformanceEntryReporter {
|
||||
}
|
||||
|
||||
void traceMark(const PerformanceMark &entry, UserTimingDetailProvider &&detailProvider) const;
|
||||
void traceMeasure(const PerformanceMeasure &entry, UserTimingDetailProvider &&detailProvider) const;
|
||||
void traceMeasure(const PerformanceMeasure &entry, const std::optional<UserTimingDetailProvider> &detailProvider)
|
||||
const;
|
||||
void traceResourceTiming(
|
||||
const PerformanceResourceTiming &entry,
|
||||
const std::optional<std::string> &devtoolsRequestId,
|
||||
|
||||
+10
-2
@@ -14,9 +14,17 @@
|
||||
|
||||
namespace facebook::react {
|
||||
|
||||
class PerformanceEntryReporterEventTimingListener {
|
||||
using UserTimingDetailProvider = std::function<folly::dynamic()>;
|
||||
|
||||
class PerformanceEntryReporterEventListener {
|
||||
public:
|
||||
virtual ~PerformanceEntryReporterEventTimingListener() = default;
|
||||
virtual ~PerformanceEntryReporterEventListener() = default;
|
||||
|
||||
virtual void onMeasureEntry(
|
||||
const PerformanceMeasure & /*entry*/,
|
||||
const std::optional<UserTimingDetailProvider> & /*detailProvider*/)
|
||||
{
|
||||
}
|
||||
|
||||
virtual void onEventTimingEntry(const PerformanceEventTiming & /*entry*/) {}
|
||||
};
|
||||
|
||||
+6
-2
@@ -196,7 +196,8 @@ TEST(PerformanceObserver, PerformanceObserverTestObserveTakeRecords) {
|
||||
reporter->reportMeasure(
|
||||
"off",
|
||||
timeOrigin + HighResDuration::fromMilliseconds(10),
|
||||
HighResDuration::fromMilliseconds(20));
|
||||
HighResDuration::fromMilliseconds(20),
|
||||
std::nullopt);
|
||||
reporter->reportMark(
|
||||
"test2", timeOrigin + HighResDuration::fromMilliseconds(20));
|
||||
reporter->reportMark(
|
||||
@@ -391,7 +392,10 @@ TEST(PerformanceObserver, PerformanceObserverTestMultiple) {
|
||||
{.durationThreshold = HighResDuration::fromMilliseconds(80)});
|
||||
|
||||
reporter->reportMeasure(
|
||||
"measure", timeOrigin, HighResDuration::fromMilliseconds(50));
|
||||
"measure",
|
||||
timeOrigin,
|
||||
HighResDuration::fromMilliseconds(50),
|
||||
std::nullopt);
|
||||
reporter->reportEvent(
|
||||
"event1",
|
||||
timeOrigin,
|
||||
|
||||
+13
-3
@@ -74,11 +74,13 @@ NativeAnimatedNodesManager::NativeAnimatedNodesManager(
|
||||
DirectManipulationCallback&& directManipulationCallback,
|
||||
FabricCommitCallback&& fabricCommitCallback,
|
||||
StartOnRenderCallback&& startOnRenderCallback,
|
||||
StopOnRenderCallback&& stopOnRenderCallback) noexcept
|
||||
StopOnRenderCallback&& stopOnRenderCallback,
|
||||
FrameRateListenerCallback&& frameRateListenerCallback) noexcept
|
||||
: directManipulationCallback_(std::move(directManipulationCallback)),
|
||||
fabricCommitCallback_(std::move(fabricCommitCallback)),
|
||||
startOnRenderCallback_(std::move(startOnRenderCallback)),
|
||||
stopOnRenderCallback_(std::move(stopOnRenderCallback)) {
|
||||
stopOnRenderCallback_(std::move(stopOnRenderCallback)),
|
||||
frameRateListenerCallback_(std::move(frameRateListenerCallback)) {
|
||||
if (!fabricCommitCallback_) {
|
||||
LOG(WARNING)
|
||||
<< "C++ Animated was setup without commit callback. This may lead to issue where buttons are not tappable when animation is driven by onScroll event.";
|
||||
@@ -541,7 +543,7 @@ void NativeAnimatedNodesManager::startRenderCallbackIfNeeded(bool isAsync) {
|
||||
}
|
||||
|
||||
if (startOnRenderCallback_) {
|
||||
startOnRenderCallback_(isAsync);
|
||||
startOnRenderCallback_([this]() { onRender(); }, isAsync);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -563,6 +565,10 @@ void NativeAnimatedNodesManager::stopRenderCallbackIfNeeded(
|
||||
if (stopOnRenderCallback_) {
|
||||
stopOnRenderCallback_(isAsync);
|
||||
}
|
||||
|
||||
if (frameRateListenerCallback_) {
|
||||
frameRateListenerCallback_(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1030,6 +1036,10 @@ void NativeAnimatedNodesManager::onRender() {
|
||||
"numActiveAnimations",
|
||||
activeAnimations_.size());
|
||||
|
||||
if (frameRateListenerCallback_) {
|
||||
frameRateListenerCallback_(true);
|
||||
}
|
||||
|
||||
isOnRenderThread_ = true;
|
||||
|
||||
{
|
||||
|
||||
+5
-2
@@ -55,14 +55,16 @@ class NativeAnimatedNodesManager {
|
||||
public:
|
||||
using DirectManipulationCallback = std::function<void(Tag, const folly::dynamic &)>;
|
||||
using FabricCommitCallback = std::function<void(std::unordered_map<Tag, folly::dynamic> &)>;
|
||||
using StartOnRenderCallback = std::function<void(bool isAsync)>;
|
||||
using StartOnRenderCallback = std::function<void(std::function<void()> &&, bool isAsync)>;
|
||||
using StopOnRenderCallback = std::function<void(bool isAsync)>;
|
||||
using FrameRateListenerCallback = std::function<void(bool /* shouldEnableListener */)>;
|
||||
|
||||
explicit NativeAnimatedNodesManager(
|
||||
DirectManipulationCallback &&directManipulationCallback,
|
||||
FabricCommitCallback &&fabricCommitCallback,
|
||||
StartOnRenderCallback &&startOnRenderCallback = nullptr,
|
||||
StopOnRenderCallback &&stopOnRenderCallback = nullptr) noexcept;
|
||||
StopOnRenderCallback &&stopOnRenderCallback = nullptr,
|
||||
FrameRateListenerCallback &&frameRateListenerCallback = nullptr) noexcept;
|
||||
|
||||
explicit NativeAnimatedNodesManager(std::shared_ptr<UIManagerAnimationBackend> animationBackend) noexcept;
|
||||
|
||||
@@ -237,6 +239,7 @@ class NativeAnimatedNodesManager {
|
||||
std::atomic_bool isRenderCallbackStarted_{false};
|
||||
const StartOnRenderCallback startOnRenderCallback_;
|
||||
const StopOnRenderCallback stopOnRenderCallback_;
|
||||
const FrameRateListenerCallback frameRateListenerCallback_;
|
||||
|
||||
std::shared_ptr<EventEmitterListener> eventEmitterListener_{nullptr};
|
||||
|
||||
|
||||
+14
-46
@@ -19,41 +19,26 @@
|
||||
namespace facebook::react {
|
||||
|
||||
UIManagerNativeAnimatedDelegateImpl::UIManagerNativeAnimatedDelegateImpl(
|
||||
NativeAnimatedNodesManagerProvider::FrameRateListenerCallback
|
||||
frameRateListenerCallback)
|
||||
: frameRateListenerCallback_(std::move(frameRateListenerCallback)) {}
|
||||
std::weak_ptr<NativeAnimatedNodesManager> manager)
|
||||
: nativeAnimatedNodesManager_(manager) {}
|
||||
|
||||
void UIManagerNativeAnimatedDelegateImpl::runAnimationFrame() {
|
||||
if (auto nativeAnimatedNodesManagerStrong =
|
||||
nativeAnimatedNodesManager_.lock()) {
|
||||
if (frameRateListenerCallback_) {
|
||||
frameRateListenerCallback_(true);
|
||||
}
|
||||
nativeAnimatedNodesManagerStrong->onRender();
|
||||
}
|
||||
}
|
||||
|
||||
NativeAnimatedNodesManagerProvider::NativeAnimatedNodesManagerProvider(
|
||||
StartOnRenderCallback startOnRenderCallback,
|
||||
StopOnRenderCallback stopOnRenderCallback,
|
||||
FrameRateListenerCallback frameRateListenerCallback)
|
||||
NativeAnimatedNodesManager::StartOnRenderCallback startOnRenderCallback,
|
||||
NativeAnimatedNodesManager::StopOnRenderCallback stopOnRenderCallback,
|
||||
NativeAnimatedNodesManager::FrameRateListenerCallback
|
||||
frameRateListenerCallback)
|
||||
: eventEmitterListenerContainer_(
|
||||
std::make_shared<EventEmitterListenerContainer>()),
|
||||
frameRateListenerCallback_(std::move(frameRateListenerCallback)),
|
||||
startOnRenderCallback_(std::move(startOnRenderCallback)) {
|
||||
if (frameRateListenerCallback_) {
|
||||
stopOnRenderCallback_ = [this, stopOnRenderCallback](bool isAsync) {
|
||||
if (stopOnRenderCallback) {
|
||||
stopOnRenderCallback(isAsync);
|
||||
}
|
||||
if (frameRateListenerCallback_) {
|
||||
frameRateListenerCallback_(false);
|
||||
}
|
||||
};
|
||||
} else {
|
||||
stopOnRenderCallback_ = std::move(stopOnRenderCallback);
|
||||
}
|
||||
}
|
||||
startOnRenderCallback_(std::move(startOnRenderCallback)),
|
||||
stopOnRenderCallback_(std::move(stopOnRenderCallback)),
|
||||
frameRateListenerCallback_(std::move(frameRateListenerCallback)) {}
|
||||
|
||||
std::shared_ptr<NativeAnimatedNodesManager>
|
||||
NativeAnimatedNodesManagerProvider::getOrCreate(
|
||||
@@ -85,10 +70,6 @@ NativeAnimatedNodesManagerProvider::getOrCreate(
|
||||
uiManager->synchronouslyUpdateViewOnUIThread(viewTag, props);
|
||||
};
|
||||
|
||||
nativeAnimatedDelegate_ =
|
||||
std::make_shared<UIManagerNativeAnimatedDelegateImpl>(
|
||||
frameRateListenerCallback_);
|
||||
|
||||
if (ReactNativeFeatureFlags::useSharedAnimatedBackend()) {
|
||||
#ifdef RN_USE_ANIMATION_BACKEND
|
||||
// TODO: this should be initialized outside of animated, but for now it
|
||||
@@ -106,31 +87,14 @@ NativeAnimatedNodesManagerProvider::getOrCreate(
|
||||
|
||||
uiManager->unstable_setAnimationBackend(animationBackend_);
|
||||
} else {
|
||||
auto startOnRenderCallback =
|
||||
[this, startOnRenderCallbackFn = std::move(startOnRenderCallback_)](
|
||||
bool isAsync) {
|
||||
if (startOnRenderCallbackFn) {
|
||||
startOnRenderCallbackFn(
|
||||
[this]() {
|
||||
if (nativeAnimatedDelegate_) {
|
||||
nativeAnimatedDelegate_->runAnimationFrame();
|
||||
}
|
||||
},
|
||||
isAsync);
|
||||
}
|
||||
};
|
||||
nativeAnimatedNodesManager_ =
|
||||
std::make_shared<NativeAnimatedNodesManager>(
|
||||
std::move(directManipulationCallback),
|
||||
std::move(fabricCommitCallback),
|
||||
std::move(startOnRenderCallback),
|
||||
std::move(startOnRenderCallback_),
|
||||
std::move(stopOnRenderCallback_));
|
||||
}
|
||||
|
||||
std::static_pointer_cast<UIManagerNativeAnimatedDelegateImpl>(
|
||||
nativeAnimatedDelegate_)
|
||||
->setNativeAnimatedNodesManager(nativeAnimatedNodesManager_);
|
||||
|
||||
addEventEmitterListener(
|
||||
nativeAnimatedNodesManager_->getEventEmitterListener());
|
||||
|
||||
@@ -153,6 +117,10 @@ NativeAnimatedNodesManagerProvider::getOrCreate(
|
||||
return false;
|
||||
}));
|
||||
|
||||
nativeAnimatedDelegate_ =
|
||||
std::make_shared<UIManagerNativeAnimatedDelegateImpl>(
|
||||
nativeAnimatedNodesManager_);
|
||||
|
||||
uiManager->setNativeAnimatedDelegate(nativeAnimatedDelegate_);
|
||||
|
||||
// TODO: remove force casting.
|
||||
|
||||
+7
-21
@@ -17,16 +17,10 @@ class AnimatedMountingOverrideDelegate;
|
||||
|
||||
class NativeAnimatedNodesManagerProvider {
|
||||
public:
|
||||
using FrameRateListenerCallback = std::function<void(bool /* shouldEnableListener */)>;
|
||||
// when isAsync is true, it means StartOnRenderCallback is invoked from js
|
||||
// thread, otherwise from main thread
|
||||
using StartOnRenderCallback = std::function<void(std::function<void()> &&, bool /* isAsync */)>;
|
||||
using StopOnRenderCallback = NativeAnimatedNodesManager::StopOnRenderCallback;
|
||||
|
||||
NativeAnimatedNodesManagerProvider(
|
||||
StartOnRenderCallback startOnRenderCallback = nullptr,
|
||||
StopOnRenderCallback stopOnRenderCallback = nullptr,
|
||||
FrameRateListenerCallback frameRateListenerCallback = nullptr);
|
||||
NativeAnimatedNodesManager::StartOnRenderCallback startOnRenderCallback = nullptr,
|
||||
NativeAnimatedNodesManager::StopOnRenderCallback stopOnRenderCallback = nullptr,
|
||||
NativeAnimatedNodesManager::FrameRateListenerCallback frameRateListenerCallback = nullptr);
|
||||
|
||||
std::shared_ptr<NativeAnimatedNodesManager> getOrCreate(
|
||||
jsi::Runtime &runtime,
|
||||
@@ -47,29 +41,21 @@ class NativeAnimatedNodesManagerProvider {
|
||||
std::shared_ptr<UIManagerNativeAnimatedDelegate> nativeAnimatedDelegate_;
|
||||
std::shared_ptr<AnimatedMountingOverrideDelegate> animatedMountingOverrideDelegate_;
|
||||
|
||||
FrameRateListenerCallback frameRateListenerCallback_;
|
||||
|
||||
StartOnRenderCallback startOnRenderCallback_;
|
||||
StopOnRenderCallback stopOnRenderCallback_;
|
||||
NativeAnimatedNodesManager::StartOnRenderCallback startOnRenderCallback_;
|
||||
NativeAnimatedNodesManager::StopOnRenderCallback stopOnRenderCallback_;
|
||||
NativeAnimatedNodesManager::FrameRateListenerCallback frameRateListenerCallback_;
|
||||
|
||||
std::unique_ptr<MergedValueDispatcher> mergedValueDispatcher_;
|
||||
};
|
||||
|
||||
class UIManagerNativeAnimatedDelegateImpl : public UIManagerNativeAnimatedDelegate {
|
||||
public:
|
||||
explicit UIManagerNativeAnimatedDelegateImpl(
|
||||
NativeAnimatedNodesManagerProvider::FrameRateListenerCallback frameRateListenerCallback);
|
||||
explicit UIManagerNativeAnimatedDelegateImpl(std::weak_ptr<NativeAnimatedNodesManager> manager);
|
||||
|
||||
void runAnimationFrame() override;
|
||||
|
||||
void setNativeAnimatedNodesManager(std::weak_ptr<NativeAnimatedNodesManager> manager)
|
||||
{
|
||||
nativeAnimatedNodesManager_ = manager;
|
||||
}
|
||||
|
||||
private:
|
||||
std::weak_ptr<NativeAnimatedNodesManager> nativeAnimatedNodesManager_;
|
||||
NativeAnimatedNodesManagerProvider::FrameRateListenerCallback frameRateListenerCallback_;
|
||||
};
|
||||
|
||||
} // namespace facebook::react
|
||||
|
||||
@@ -74,6 +74,24 @@ void ImageShadowNode::updateStateIfNeeded() {
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef ANDROID
|
||||
// Check if we should skip prefetching based on shouldResize logic
|
||||
if (ReactNativeFeatureFlags::enableImagePrefetchingAndroid()) {
|
||||
const auto& resizeMethod = imageProps.resizeMethod;
|
||||
const auto& uri = newImageSource.uri;
|
||||
bool shouldResize = (resizeMethod == "resize") ||
|
||||
// Only resize for local content/file URIs
|
||||
(resizeMethod == "auto" &&
|
||||
(uri.starts_with("content://") || uri.starts_with("file://")));
|
||||
// If we would resize but have no dimensions, skip creating the request
|
||||
if (shouldResize &&
|
||||
(newImageSource.size.width == 0 || newImageSource.size.height == 0)) {
|
||||
// Keep the old state - don't create a new image request
|
||||
return;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
ImageState state{
|
||||
newImageSource,
|
||||
imageManager_->requestImage(
|
||||
|
||||
@@ -421,7 +421,7 @@ std::shared_ptr<ShadowNode> cloneMultipleRecursive(
|
||||
std::shared_ptr<std::vector<std::shared_ptr<const ShadowNode>>> newChildren;
|
||||
auto count = childrenCount.at(family);
|
||||
|
||||
for (int i = 0; count > 0 && i < children.size(); i++) {
|
||||
for (size_t i = 0; count > 0 && i < children.size(); i++) {
|
||||
const auto childFamily = &children[i]->getFamily();
|
||||
if (childrenCount.contains(childFamily)) {
|
||||
count--;
|
||||
|
||||
@@ -41,7 +41,12 @@ Scheduler::Scheduler(
|
||||
if (ReactNativeFeatureFlags::enableBridgelessArchitecture() &&
|
||||
ReactNativeFeatureFlags::cdpInteractionMetricsEnabled()) {
|
||||
cdpMetricsReporter_.emplace(CdpMetricsReporter{runtimeExecutor_});
|
||||
performanceEntryReporter_->addEventTimingListener(&*cdpMetricsReporter_);
|
||||
performanceEntryReporter_->addEventListener(&*cdpMetricsReporter_);
|
||||
}
|
||||
|
||||
if (ReactNativeFeatureFlags::perfIssuesEnabled()) {
|
||||
cdpPerfIssuesReporter_.emplace(CdpPerfIssuesReporter{runtimeExecutor_});
|
||||
performanceEntryReporter_->addEventListener(&*cdpPerfIssuesReporter_);
|
||||
}
|
||||
|
||||
eventPerformanceLogger_ =
|
||||
@@ -172,7 +177,10 @@ Scheduler::~Scheduler() {
|
||||
uiManager_->setAnimationDelegate(nullptr);
|
||||
|
||||
if (cdpMetricsReporter_) {
|
||||
performanceEntryReporter_->removeEventTimingListener(&*cdpMetricsReporter_);
|
||||
performanceEntryReporter_->removeEventListener(&*cdpMetricsReporter_);
|
||||
}
|
||||
if (cdpPerfIssuesReporter_) {
|
||||
performanceEntryReporter_->removeEventListener(&*cdpPerfIssuesReporter_);
|
||||
}
|
||||
|
||||
// Then, let's verify that the requirement was satisfied.
|
||||
@@ -283,8 +291,8 @@ void Scheduler::uiManagerDidDispatchCommand(
|
||||
const std::shared_ptr<const ShadowNode>& shadowNode,
|
||||
const std::string& commandName,
|
||||
const folly::dynamic& args) {
|
||||
TraceSection s("Scheduler::uiManagerDispatchCommand");
|
||||
|
||||
TraceSection s(
|
||||
"Scheduler::uiManagerDispatchCommand", "commandName", commandName);
|
||||
if (delegate_ != nullptr) {
|
||||
auto shadowView = ShadowView(*shadowNode);
|
||||
runtimeScheduler_->scheduleRenderingUpdate(
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
|
||||
#include <ReactCommon/RuntimeExecutor.h>
|
||||
#include <react/performance/cdpmetrics/CdpMetricsReporter.h>
|
||||
#include <react/performance/cdpmetrics/CdpPerfIssuesReporter.h>
|
||||
#include <react/performance/timeline/PerformanceEntryReporter.h>
|
||||
#include <react/renderer/componentregistry/ComponentDescriptorFactory.h>
|
||||
#include <react/renderer/core/ComponentDescriptor.h>
|
||||
@@ -134,6 +135,7 @@ class Scheduler final : public UIManagerDelegate {
|
||||
|
||||
std::shared_ptr<PerformanceEntryReporter> performanceEntryReporter_;
|
||||
std::optional<CdpMetricsReporter> cdpMetricsReporter_;
|
||||
std::optional<CdpPerfIssuesReporter> cdpPerfIssuesReporter_;
|
||||
std::shared_ptr<EventPerformanceLogger> eventPerformanceLogger_;
|
||||
|
||||
/**
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user