Skip to content

Commit 84f9e48

Browse files
sammy-SCfacebook-github-bot
authored andcommitted
Fix a crash in View Culling coming from unflattening/flattening algorith (facebook#51907)
Summary: Pull Request resolved: facebook#51907 changelog: [internal] fixes a crash that is described by the two tests. The two tests cover both changes made to Differentiator.cpp. If you revert either of the change, a test will crash. Reviewed By: christophpurrer Differential Revision: D76231984 fbshipit-source-id: c32ab1851844121095f1dec953befb2e77c83fd4
1 parent 38a4b62 commit 84f9e48

2 files changed

Lines changed: 123 additions & 2 deletions

File tree

packages/react-native/Libraries/Components/ScrollView/__tests__/ScrollView-viewCulling-itest.js

Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2327,6 +2327,126 @@ describe('reparenting', () => {
23272327
'Insert {type: "View", parentNativeID: "grandchild", index: 0, nativeID: "grandgrandchild"}',
23282328
]);
23292329
});
2330+
2331+
test('parent-child flattening with deep hierarchy', () => {
2332+
function renderTree(root: Fantom.Root, isFinal: boolean) {
2333+
Fantom.runTask(() => {
2334+
root.render(
2335+
<ScrollView
2336+
style={{height: 100, width: 100}}
2337+
contentOffset={{x: 0, y: 52}}>
2338+
<View
2339+
style={{
2340+
marginTop: isFinal ? 92 : 100,
2341+
opacity: isFinal ? 0 : undefined,
2342+
}}>
2343+
<View
2344+
style={{
2345+
marginTop: 50,
2346+
opacity: isFinal ? 0 : undefined,
2347+
}}>
2348+
<View collapsable={false} style={{height: 10, width: 10}}>
2349+
<View
2350+
collapsable={false}
2351+
style={{height: 5, width: 5, marginTop: 5}}>
2352+
<View
2353+
nativeID="child"
2354+
style={{height: 2.5, width: 2.5, marginTop: 2.5}}
2355+
/>
2356+
</View>
2357+
</View>
2358+
</View>
2359+
</View>
2360+
</ScrollView>,
2361+
);
2362+
});
2363+
}
2364+
2365+
const root = Fantom.createRoot({viewportWidth: 100, viewportHeight: 100});
2366+
2367+
renderTree(root, false);
2368+
2369+
expect(root.takeMountingManagerLogs()).not.toContain(
2370+
'Create {type: "View", nativeID: "child"}',
2371+
);
2372+
2373+
renderTree(root, true);
2374+
2375+
expect(root.takeMountingManagerLogs()).toContain(
2376+
'Create {type: "View", nativeID: "child"}',
2377+
);
2378+
2379+
const finalRoot = Fantom.createRoot({
2380+
viewportWidth: 100,
2381+
viewportHeight: 100,
2382+
});
2383+
2384+
renderTree(finalRoot, true);
2385+
2386+
expect(root.getRenderedOutput().toJSON).toEqual(
2387+
finalRoot.getRenderedOutput().toJSON,
2388+
);
2389+
});
2390+
2391+
test('parent-child unflattening with deep hierarchy', () => {
2392+
function renderTree(root: Fantom.Root, isFinal: boolean) {
2393+
Fantom.runTask(() => {
2394+
root.render(
2395+
<ScrollView
2396+
style={{height: 100, width: 100}}
2397+
contentOffset={{x: 0, y: 52}}>
2398+
<View
2399+
style={{
2400+
marginTop: isFinal ? 92 : 100,
2401+
opacity: isFinal ? undefined : 0,
2402+
}}>
2403+
<View
2404+
style={{
2405+
marginTop: 50,
2406+
opacity: isFinal ? undefined : 0,
2407+
}}>
2408+
<View collapsable={false} style={{height: 10, width: 10}}>
2409+
<View
2410+
collapsable={false}
2411+
style={{height: 5, width: 5, marginTop: 5}}>
2412+
<View
2413+
nativeID="child"
2414+
style={{height: 2.5, width: 2.5, marginTop: 2.5}}
2415+
/>
2416+
</View>
2417+
</View>
2418+
</View>
2419+
</View>
2420+
</ScrollView>,
2421+
);
2422+
});
2423+
}
2424+
2425+
const root = Fantom.createRoot({viewportWidth: 100, viewportHeight: 100});
2426+
2427+
renderTree(root, false);
2428+
2429+
expect(root.takeMountingManagerLogs()).not.toContain(
2430+
'Create {type: "View", nativeID: "child"}',
2431+
);
2432+
2433+
renderTree(root, true);
2434+
2435+
expect(root.takeMountingManagerLogs()).toContain(
2436+
'Create {type: "View", nativeID: "child"}',
2437+
);
2438+
2439+
const finalRoot = Fantom.createRoot({
2440+
viewportWidth: 100,
2441+
viewportHeight: 100,
2442+
});
2443+
2444+
renderTree(finalRoot, true);
2445+
2446+
expect(root.getRenderedOutput().toJSON).toEqual(
2447+
finalRoot.getRenderedOutput().toJSON,
2448+
);
2449+
});
23302450
});
23312451

23322452
describe('opt out mechanism - Unstable_uncullableView & Unstable_uncullableTrace', () => {

packages/react-native/ReactCommon/react/renderer/mounting/Differentiator.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -630,7 +630,8 @@ static void calculateShadowViewMutationsFlattener(
630630

631631
// Update children if appropriate.
632632
if (!oldTreeNodePair.flattened && !newTreeNodePair.flattened) {
633-
if (oldTreeNodePair.shadowNode != newTreeNodePair.shadowNode) {
633+
if (oldTreeNodePair.shadowNode != newTreeNodePair.shadowNode ||
634+
adjustedOldCullingContext != adjustedNewCullingContext) {
634635
ViewNodePairScope innerScope{};
635636
auto oldGrandChildPairs =
636637
sliceChildShadowNodeViewPairsFromViewNodePair(
@@ -678,7 +679,7 @@ static void calculateShadowViewMutationsFlattener(
678679
: parentTag),
679680
subVisitedNewMap,
680681
subVisitedOldMap,
681-
cullingContext,
682+
cullingContextForUnvisitedOtherNodes,
682683
cullingContext.adjustCullingContextIfNeeded(treeChildPair));
683684
} else {
684685
// Get flattened nodes from either new or old tree

0 commit comments

Comments
 (0)