Fix possible invalid measurements when width or height is zero pixels (#1820)

Summary:
X-link: https://github.com/facebook/react-native/pull/52073

Pull Request resolved: https://github.com/facebook/yoga/pull/1820

Fixes https://github.com/facebook/yoga/issues/1819

Yoga has a fast path when measuring a node, if it thinks it knows its dimensions ahead of time.

This path has some eroneous logic, to set both axis to owner size, if *either* will evaluate to zero, while having an `YGMeasureModeAtMost`/`FitContent` constraint. This means that if a node is given a zero width, and Yoga later measures with with `FitContent`, its height will become the maximum allowable height, even if it shouldn't be that large.

We can fix this, by only allowing if both axis are this fixed case, instead of just one.

This bug has existed for about a decade (going back to at least D3312496).

Changelog:
[General][Fixed] - Fix possible invalid measurements with width or height is zero pixels

Reviewed By: yungsters

Differential Revision: D76793705

fbshipit-source-id: ea4c00e688912a58c08801e4a14ddf1b293a5d86
This commit is contained in:
Nick Gerleman
2025-06-17 12:15:55 -07:00
committed by Facebook GitHub Bot
parent 117fa494f7
commit 27d632c697
5 changed files with 268 additions and 9 deletions

View File

@@ -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<<075a0b67003e5c4a1f51bd99da71c700>>
* @generated SignedSource<<fd80af208d8635435f86ffa8f3810b39>>
* generated by gentest/gentest-driver.ts from gentest/fixtures/YGAlignItemsTest.html
*/
@@ -2442,3 +2442,88 @@ test('align_stretch_with_row_reverse', () => {
config.free();
}
});
test('align_items_non_stretch_s526008', () => {
const config = Yoga.Config.create();
let root;
try {
root = Yoga.Node.create(config);
root.setPositionType(PositionType.Absolute);
root.setWidth(400);
root.setHeight(400);
const root_child0 = Yoga.Node.create(config);
root_child0.setFlexDirection(FlexDirection.Row);
root.insertChild(root_child0, 0);
const root_child0_child0 = Yoga.Node.create(config);
root_child0_child0.setAlignItems(Align.FlexStart);
root_child0.insertChild(root_child0_child0, 0);
const root_child0_child0_child0 = Yoga.Node.create(config);
root_child0_child0.insertChild(root_child0_child0_child0, 0);
const root_child0_child0_child0_child0 = Yoga.Node.create(config);
root_child0_child0_child0_child0.setHeight(10);
root_child0_child0_child0.insertChild(root_child0_child0_child0_child0, 0);
root.calculateLayout(undefined, undefined, Direction.LTR);
expect(root.getComputedLeft()).toBe(0);
expect(root.getComputedTop()).toBe(0);
expect(root.getComputedWidth()).toBe(400);
expect(root.getComputedHeight()).toBe(400);
expect(root_child0.getComputedLeft()).toBe(0);
expect(root_child0.getComputedTop()).toBe(0);
expect(root_child0.getComputedWidth()).toBe(400);
expect(root_child0.getComputedHeight()).toBe(10);
expect(root_child0_child0.getComputedLeft()).toBe(0);
expect(root_child0_child0.getComputedTop()).toBe(0);
expect(root_child0_child0.getComputedWidth()).toBe(0);
expect(root_child0_child0.getComputedHeight()).toBe(10);
expect(root_child0_child0_child0.getComputedLeft()).toBe(0);
expect(root_child0_child0_child0.getComputedTop()).toBe(0);
expect(root_child0_child0_child0.getComputedWidth()).toBe(0);
expect(root_child0_child0_child0.getComputedHeight()).toBe(10);
expect(root_child0_child0_child0_child0.getComputedLeft()).toBe(0);
expect(root_child0_child0_child0_child0.getComputedTop()).toBe(0);
expect(root_child0_child0_child0_child0.getComputedWidth()).toBe(0);
expect(root_child0_child0_child0_child0.getComputedHeight()).toBe(10);
root.calculateLayout(undefined, undefined, Direction.RTL);
expect(root.getComputedLeft()).toBe(0);
expect(root.getComputedTop()).toBe(0);
expect(root.getComputedWidth()).toBe(400);
expect(root.getComputedHeight()).toBe(400);
expect(root_child0.getComputedLeft()).toBe(0);
expect(root_child0.getComputedTop()).toBe(0);
expect(root_child0.getComputedWidth()).toBe(400);
expect(root_child0.getComputedHeight()).toBe(10);
expect(root_child0_child0.getComputedLeft()).toBe(400);
expect(root_child0_child0.getComputedTop()).toBe(0);
expect(root_child0_child0.getComputedWidth()).toBe(0);
expect(root_child0_child0.getComputedHeight()).toBe(10);
expect(root_child0_child0_child0.getComputedLeft()).toBe(0);
expect(root_child0_child0_child0.getComputedTop()).toBe(0);
expect(root_child0_child0_child0.getComputedWidth()).toBe(0);
expect(root_child0_child0_child0.getComputedHeight()).toBe(10);
expect(root_child0_child0_child0_child0.getComputedLeft()).toBe(0);
expect(root_child0_child0_child0_child0.getComputedTop()).toBe(0);
expect(root_child0_child0_child0_child0.getComputedWidth()).toBe(0);
expect(root_child0_child0_child0_child0.getComputedHeight()).toBe(10);
} finally {
if (typeof root !== 'undefined') {
root.freeRecursive();
}
config.free();
}
});