From cbc327ce53fb9d431849b75ba2bccc684fb8dd7d Mon Sep 17 00:00:00 2001 From: Samuel Susla Date: Wed, 11 Jun 2025 06:35:28 -0700 Subject: [PATCH] Disable view culling in ScrollView with overflow visible (#51947) Summary: Pull Request resolved: https://github.com/facebook/react-native/pull/51947 changelog: [internal] disable view culling if ScrollView has overflow set to visible Reviewed By: rubennorte Differential Revision: D76419519 fbshipit-source-id: 002bde2ab4dda0fc635ae04cb4e34390a0e13d80 --- .../__tests__/ScrollView-viewCulling-itest.js | 22 +++++++++++++++++++ .../mounting/internal/CullingContext.cpp | 17 +++++++++----- 2 files changed, 33 insertions(+), 6 deletions(-) diff --git a/packages/react-native/Libraries/Components/ScrollView/__tests__/ScrollView-viewCulling-itest.js b/packages/react-native/Libraries/Components/ScrollView/__tests__/ScrollView-viewCulling-itest.js index 43be9bac989..3c33c659e72 100644 --- a/packages/react-native/Libraries/Components/ScrollView/__tests__/ScrollView-viewCulling-itest.js +++ b/packages/react-native/Libraries/Components/ScrollView/__tests__/ScrollView-viewCulling-itest.js @@ -2534,3 +2534,25 @@ describe('opt out mechanism - Unstable_uncullableView & Unstable_uncullableTrace ); }); }); + +describe('culling inside ScrollView with overflow visible', () => { + it('shows view outside of bounds', () => { + const root = Fantom.createRoot({viewportWidth: 100, viewportHeight: 100}); + + Fantom.runTask(() => { + root.render( + + + , + ); + }); + + // Child is not culled because overflow:visible. + expect(root.takeMountingManagerLogs()).toContain( + 'Create {type: "View", nativeID: "child"}', + ); + }); +}); diff --git a/packages/react-native/ReactCommon/react/renderer/mounting/internal/CullingContext.cpp b/packages/react-native/ReactCommon/react/renderer/mounting/internal/CullingContext.cpp index b90414be6dd..b061451ac0f 100644 --- a/packages/react-native/ReactCommon/react/renderer/mounting/internal/CullingContext.cpp +++ b/packages/react-native/ReactCommon/react/renderer/mounting/internal/CullingContext.cpp @@ -23,12 +23,17 @@ CullingContext CullingContext::adjustCullingContextIfNeeded( if (ReactNativeFeatureFlags::enableViewCulling()) { if (auto scrollViewShadowNode = dynamic_cast(pair.shadowNode)) { - cullingContext.frame.origin = - -scrollViewShadowNode->getContentOriginOffset( - /* includeTransform */ true); - cullingContext.frame.size = - scrollViewShadowNode->getLayoutMetrics().frame.size; - cullingContext.transform = Transform::Identity(); + if (scrollViewShadowNode->getConcreteProps().yogaStyle.overflow() != + yoga::Overflow::Visible) { + cullingContext.frame.origin = + -scrollViewShadowNode->getContentOriginOffset( + /* includeTransform */ true); + cullingContext.frame.size = + scrollViewShadowNode->getLayoutMetrics().frame.size; + cullingContext.transform = Transform::Identity(); + } else { + cullingContext = {}; + } } else if (pair.shadowView.traits.check( ShadowNodeTraits::Trait::RootNodeKind)) { cullingContext = {};