From e90fd0847d1718e7adaa0c5b8b3c5e21c7dae969 Mon Sep 17 00:00:00 2001 From: Santhosh Kumar Date: Wed, 7 May 2025 15:01:06 +0200 Subject: [PATCH 01/32] Fix documentation of 'alignContent' property specifically configured with spaces. --- website/docs/styling/align-content.mdx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/website/docs/styling/align-content.mdx b/website/docs/styling/align-content.mdx index e7409723..f06345e1 100644 --- a/website/docs/styling/align-content.mdx +++ b/website/docs/styling/align-content.mdx @@ -17,15 +17,15 @@ has effect when items are wrapped to multiple lines using [flex wrap](/docs/styl **Center**: Align wrapped lines in the center of the container's cross axis. -**Space between**: Evenly space wrapped lines across the container's main axis, distributing +**Space between**: Evenly space wrapped lines across the container's cross axis, distributing remaining space between the lines. -**Space around**: Evenly space wrapped lines across the container's main axis, distributing +**Space around**: Evenly space wrapped lines across the container's cross axis, distributing remaining space around the lines. Compared to space between using space around will result in space being distributed to the beginning of the first lines and end of the last line. -**Space evenly**: Evenly space wrapped lines across the container's main axis, distributing +**Space evenly**: Evenly space wrapped lines across the container's cross axis, distributing remaining space around the lines. Compared to space around, space evenly will not double the gaps between children. The size of gaps between children and between the parent's edges and the first/last child will all be equal. -- 2.50.1.windows.1 From 4abc1a7d5fcc64c3a415d1a0dd6b11988e8e576e Mon Sep 17 00:00:00 2001 From: Santhosh Kumar Date: Wed, 7 May 2025 14:40:02 -0700 Subject: [PATCH 02/32] Fix documentation of 'alignContent' property configured with spaces (#1808) Summary: The documentation shall be corrected to specify in which axis the spaces are distributed when flex container is configured 'alignContent' property. Pull Request resolved: https://github.com/facebook/yoga/pull/1808 Reviewed By: joevilches Differential Revision: D74347272 Pulled By: philIip fbshipit-source-id: 1b05840028bca774c9d4a68562bcf537d5a72500 --- website/docs/styling/align-content.mdx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/website/docs/styling/align-content.mdx b/website/docs/styling/align-content.mdx index e7409723..f06345e1 100644 --- a/website/docs/styling/align-content.mdx +++ b/website/docs/styling/align-content.mdx @@ -17,15 +17,15 @@ has effect when items are wrapped to multiple lines using [flex wrap](/docs/styl **Center**: Align wrapped lines in the center of the container's cross axis. -**Space between**: Evenly space wrapped lines across the container's main axis, distributing +**Space between**: Evenly space wrapped lines across the container's cross axis, distributing remaining space between the lines. -**Space around**: Evenly space wrapped lines across the container's main axis, distributing +**Space around**: Evenly space wrapped lines across the container's cross axis, distributing remaining space around the lines. Compared to space between using space around will result in space being distributed to the beginning of the first lines and end of the last line. -**Space evenly**: Evenly space wrapped lines across the container's main axis, distributing +**Space evenly**: Evenly space wrapped lines across the container's cross axis, distributing remaining space around the lines. Compared to space around, space evenly will not double the gaps between children. The size of gaps between children and between the parent's edges and the first/last child will all be equal. -- 2.50.1.windows.1 From 37a94a86de75845b4ad301d742dd68b1f5fa8bbb Mon Sep 17 00:00:00 2001 From: Nick Gerleman Date: Thu, 8 May 2025 17:45:16 -0700 Subject: [PATCH 03/32] Expose Unsnapped Dimensions (#1809) Summary: Pull Request resolved: https://github.com/facebook/yoga/pull/1809 X-link: https://github.com/facebook/react-native/pull/51181 We want to know if an artifact created during measurement can fully be reused after final layout, but the final layout is allowed to be slightly larger due to pixel grid rounding (while still allowing reuse). It's hard to tell after the fact, whether it is larger because of this rounding (though the measure is used), or if it may be a pixel larger for valid reasons. We can expose the unsnapped dimensions of a node to give us this information, and to correlate measurement artifacts. This is most of the time the same as the layout's measured dimension, though I don't think it's safe to use this, since anything else measuring the node after could clobber this (I think `YGNodeLayoutGetOverflow` may also be prone to this as a bug). Changelog: [Internal] Reviewed By: rshest Differential Revision: D74292949 fbshipit-source-id: 05011c66a9a9480544313eb1dfe2c46bf7742bac --- tests/YGRoundingFunctionTest.cpp | 20 ++++++++++++++++++++ yoga/YGNodeLayout.cpp | 8 ++++++++ yoga/YGNodeLayout.h | 10 ++++++++++ yoga/algorithm/PixelGrid.cpp | 12 ++++++------ yoga/node/LayoutResults.h | 9 +++++++++ yoga/node/Node.cpp | 1 + 6 files changed, 54 insertions(+), 6 deletions(-) diff --git a/tests/YGRoundingFunctionTest.cpp b/tests/YGRoundingFunctionTest.cpp index 55b5e86d..47efcbc4 100644 --- a/tests/YGRoundingFunctionTest.cpp +++ b/tests/YGRoundingFunctionTest.cpp @@ -161,3 +161,23 @@ TEST(YogaTest, per_node_point_scale_factor) { YGConfigFree(config2); YGConfigFree(config3); } + +TEST(YogaTest, raw_layout_dimensions) { + YGConfigRef config = YGConfigNew(); + YGConfigSetPointScaleFactor(config, 0.5f); + + YGNodeRef root = YGNodeNewWithConfig(config); + YGNodeStyleSetWidth(root, 11.5f); + YGNodeStyleSetHeight(root, 9.5f); + + YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR); + + ASSERT_EQ(YGNodeLayoutGetWidth(root), 12.0f); + ASSERT_EQ(YGNodeLayoutGetHeight(root), 10.0f); + ASSERT_EQ(YGNodeLayoutGetRawWidth(root), 11.5f); + ASSERT_EQ(YGNodeLayoutGetRawHeight(root), 9.5f); + + YGNodeFreeRecursive(root); + + YGConfigFree(config); +} diff --git a/yoga/YGNodeLayout.cpp b/yoga/YGNodeLayout.cpp index 93fcf0ad..50c8766e 100644 --- a/yoga/YGNodeLayout.cpp +++ b/yoga/YGNodeLayout.cpp @@ -90,3 +90,11 @@ float YGNodeLayoutGetPadding(YGNodeConstRef node, YGEdge edge) { return getResolvedLayoutProperty<&LayoutResults::padding>( node, scopedEnum(edge)); } + +float YGNodeLayoutGetRawHeight(YGNodeConstRef node) { + return resolveRef(node)->getLayout().rawDimension(Dimension::Height); +} + +float YGNodeLayoutGetRawWidth(YGNodeConstRef node) { + return resolveRef(node)->getLayout().rawDimension(Dimension::Width); +} diff --git a/yoga/YGNodeLayout.h b/yoga/YGNodeLayout.h index 02ead588..4f25af21 100644 --- a/yoga/YGNodeLayout.h +++ b/yoga/YGNodeLayout.h @@ -32,4 +32,14 @@ YG_EXPORT float YGNodeLayoutGetMargin(YGNodeConstRef node, YGEdge edge); YG_EXPORT float YGNodeLayoutGetBorder(YGNodeConstRef node, YGEdge edge); YG_EXPORT float YGNodeLayoutGetPadding(YGNodeConstRef node, YGEdge edge); +/** + * Return the measured height of the node, before layout rounding + */ +YG_EXPORT float YGNodeLayoutGetRawHeight(YGNodeConstRef node); + +/** + * Return the measured width of the node, before layout rounding + */ +YG_EXPORT float YGNodeLayoutGetRawWidth(YGNodeConstRef node); + YG_EXTERN_C_END diff --git a/yoga/algorithm/PixelGrid.cpp b/yoga/algorithm/PixelGrid.cpp index 6083f0f2..61de2be2 100644 --- a/yoga/algorithm/PixelGrid.cpp +++ b/yoga/algorithm/PixelGrid.cpp @@ -106,25 +106,25 @@ void roundLayoutResultsToPixelGrid( const bool hasFractionalHeight = !yoga::inexactEquals(round(scaledNodeHeight), scaledNodeHeight); - node->setLayoutDimension( + node->getLayout().setDimension( + Dimension::Width, roundValueToPixelGrid( absoluteNodeRight, pointScaleFactor, (textRounding && hasFractionalWidth), (textRounding && !hasFractionalWidth)) - roundValueToPixelGrid( - absoluteNodeLeft, pointScaleFactor, false, textRounding), - Dimension::Width); + absoluteNodeLeft, pointScaleFactor, false, textRounding)); - node->setLayoutDimension( + node->getLayout().setDimension( + Dimension::Height, roundValueToPixelGrid( absoluteNodeBottom, pointScaleFactor, (textRounding && hasFractionalHeight), (textRounding && !hasFractionalHeight)) - roundValueToPixelGrid( - absoluteNodeTop, pointScaleFactor, false, textRounding), - Dimension::Height); + absoluteNodeTop, pointScaleFactor, false, textRounding)); } for (yoga::Node* child : node->getChildren()) { diff --git a/yoga/node/LayoutResults.h b/yoga/node/LayoutResults.h index 9f0aeaf7..6776a423 100644 --- a/yoga/node/LayoutResults.h +++ b/yoga/node/LayoutResults.h @@ -66,10 +66,18 @@ struct LayoutResults { return measuredDimensions_[yoga::to_underlying(axis)]; } + float rawDimension(Dimension axis) const { + return rawDimensions_[yoga::to_underlying(axis)]; + } + void setMeasuredDimension(Dimension axis, float dimension) { measuredDimensions_[yoga::to_underlying(axis)] = dimension; } + void setRawDimension(Dimension axis, float dimension) { + rawDimensions_[yoga::to_underlying(axis)] = dimension; + } + float position(PhysicalEdge physicalEdge) const { return position_[yoga::to_underlying(physicalEdge)]; } @@ -113,6 +121,7 @@ struct LayoutResults { std::array dimensions_ = {{YGUndefined, YGUndefined}}; std::array measuredDimensions_ = {{YGUndefined, YGUndefined}}; + std::array rawDimensions_ = {{YGUndefined, YGUndefined}}; std::array position_ = {}; std::array margin_ = {}; std::array border_ = {}; diff --git a/yoga/node/Node.cpp b/yoga/node/Node.cpp index dce42fb1..fbdf5c1b 100644 --- a/yoga/node/Node.cpp +++ b/yoga/node/Node.cpp @@ -247,6 +247,7 @@ void Node::setLayoutHadOverflow(bool hadOverflow) { void Node::setLayoutDimension(float lengthValue, Dimension dimension) { layout_.setDimension(dimension, lengthValue); + layout_.setRawDimension(dimension, lengthValue); } // If both left and right are defined, then use left. Otherwise return +left or -- 2.50.1.windows.1 From 624325302ca976f787158b709e16e7495b8575fe Mon Sep 17 00:00:00 2001 From: Yannick Loriot Date: Fri, 9 May 2025 01:45:16 -0700 Subject: [PATCH 04/32] Revert D74292949: Expose Unsnapped Dimensions Differential Revision: D74292949 Original commit changeset: 05011c66a9a9 Original Phabricator Diff: D74292949 fbshipit-source-id: c6ca51c7b882950d54b6a43e206973774db40429 --- tests/YGRoundingFunctionTest.cpp | 20 -------------------- yoga/YGNodeLayout.cpp | 8 -------- yoga/YGNodeLayout.h | 10 ---------- yoga/algorithm/PixelGrid.cpp | 12 ++++++------ yoga/node/LayoutResults.h | 9 --------- yoga/node/Node.cpp | 1 - 6 files changed, 6 insertions(+), 54 deletions(-) diff --git a/tests/YGRoundingFunctionTest.cpp b/tests/YGRoundingFunctionTest.cpp index 47efcbc4..55b5e86d 100644 --- a/tests/YGRoundingFunctionTest.cpp +++ b/tests/YGRoundingFunctionTest.cpp @@ -161,23 +161,3 @@ TEST(YogaTest, per_node_point_scale_factor) { YGConfigFree(config2); YGConfigFree(config3); } - -TEST(YogaTest, raw_layout_dimensions) { - YGConfigRef config = YGConfigNew(); - YGConfigSetPointScaleFactor(config, 0.5f); - - YGNodeRef root = YGNodeNewWithConfig(config); - YGNodeStyleSetWidth(root, 11.5f); - YGNodeStyleSetHeight(root, 9.5f); - - YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR); - - ASSERT_EQ(YGNodeLayoutGetWidth(root), 12.0f); - ASSERT_EQ(YGNodeLayoutGetHeight(root), 10.0f); - ASSERT_EQ(YGNodeLayoutGetRawWidth(root), 11.5f); - ASSERT_EQ(YGNodeLayoutGetRawHeight(root), 9.5f); - - YGNodeFreeRecursive(root); - - YGConfigFree(config); -} diff --git a/yoga/YGNodeLayout.cpp b/yoga/YGNodeLayout.cpp index 50c8766e..93fcf0ad 100644 --- a/yoga/YGNodeLayout.cpp +++ b/yoga/YGNodeLayout.cpp @@ -90,11 +90,3 @@ float YGNodeLayoutGetPadding(YGNodeConstRef node, YGEdge edge) { return getResolvedLayoutProperty<&LayoutResults::padding>( node, scopedEnum(edge)); } - -float YGNodeLayoutGetRawHeight(YGNodeConstRef node) { - return resolveRef(node)->getLayout().rawDimension(Dimension::Height); -} - -float YGNodeLayoutGetRawWidth(YGNodeConstRef node) { - return resolveRef(node)->getLayout().rawDimension(Dimension::Width); -} diff --git a/yoga/YGNodeLayout.h b/yoga/YGNodeLayout.h index 4f25af21..02ead588 100644 --- a/yoga/YGNodeLayout.h +++ b/yoga/YGNodeLayout.h @@ -32,14 +32,4 @@ YG_EXPORT float YGNodeLayoutGetMargin(YGNodeConstRef node, YGEdge edge); YG_EXPORT float YGNodeLayoutGetBorder(YGNodeConstRef node, YGEdge edge); YG_EXPORT float YGNodeLayoutGetPadding(YGNodeConstRef node, YGEdge edge); -/** - * Return the measured height of the node, before layout rounding - */ -YG_EXPORT float YGNodeLayoutGetRawHeight(YGNodeConstRef node); - -/** - * Return the measured width of the node, before layout rounding - */ -YG_EXPORT float YGNodeLayoutGetRawWidth(YGNodeConstRef node); - YG_EXTERN_C_END diff --git a/yoga/algorithm/PixelGrid.cpp b/yoga/algorithm/PixelGrid.cpp index 61de2be2..6083f0f2 100644 --- a/yoga/algorithm/PixelGrid.cpp +++ b/yoga/algorithm/PixelGrid.cpp @@ -106,25 +106,25 @@ void roundLayoutResultsToPixelGrid( const bool hasFractionalHeight = !yoga::inexactEquals(round(scaledNodeHeight), scaledNodeHeight); - node->getLayout().setDimension( - Dimension::Width, + node->setLayoutDimension( roundValueToPixelGrid( absoluteNodeRight, pointScaleFactor, (textRounding && hasFractionalWidth), (textRounding && !hasFractionalWidth)) - roundValueToPixelGrid( - absoluteNodeLeft, pointScaleFactor, false, textRounding)); + absoluteNodeLeft, pointScaleFactor, false, textRounding), + Dimension::Width); - node->getLayout().setDimension( - Dimension::Height, + node->setLayoutDimension( roundValueToPixelGrid( absoluteNodeBottom, pointScaleFactor, (textRounding && hasFractionalHeight), (textRounding && !hasFractionalHeight)) - roundValueToPixelGrid( - absoluteNodeTop, pointScaleFactor, false, textRounding)); + absoluteNodeTop, pointScaleFactor, false, textRounding), + Dimension::Height); } for (yoga::Node* child : node->getChildren()) { diff --git a/yoga/node/LayoutResults.h b/yoga/node/LayoutResults.h index 6776a423..9f0aeaf7 100644 --- a/yoga/node/LayoutResults.h +++ b/yoga/node/LayoutResults.h @@ -66,18 +66,10 @@ struct LayoutResults { return measuredDimensions_[yoga::to_underlying(axis)]; } - float rawDimension(Dimension axis) const { - return rawDimensions_[yoga::to_underlying(axis)]; - } - void setMeasuredDimension(Dimension axis, float dimension) { measuredDimensions_[yoga::to_underlying(axis)] = dimension; } - void setRawDimension(Dimension axis, float dimension) { - rawDimensions_[yoga::to_underlying(axis)] = dimension; - } - float position(PhysicalEdge physicalEdge) const { return position_[yoga::to_underlying(physicalEdge)]; } @@ -121,7 +113,6 @@ struct LayoutResults { std::array dimensions_ = {{YGUndefined, YGUndefined}}; std::array measuredDimensions_ = {{YGUndefined, YGUndefined}}; - std::array rawDimensions_ = {{YGUndefined, YGUndefined}}; std::array position_ = {}; std::array margin_ = {}; std::array border_ = {}; diff --git a/yoga/node/Node.cpp b/yoga/node/Node.cpp index fbdf5c1b..dce42fb1 100644 --- a/yoga/node/Node.cpp +++ b/yoga/node/Node.cpp @@ -247,7 +247,6 @@ void Node::setLayoutHadOverflow(bool hadOverflow) { void Node::setLayoutDimension(float lengthValue, Dimension dimension) { layout_.setDimension(dimension, lengthValue); - layout_.setRawDimension(dimension, lengthValue); } // If both left and right are defined, then use left. Otherwise return +left or -- 2.50.1.windows.1 From c935fd5e1067cf3e7e3543b8b5fb1ef53d7a0b62 Mon Sep 17 00:00:00 2001 From: Nick Gerleman Date: Tue, 13 May 2025 18:21:04 -0700 Subject: [PATCH 05/32] Resubmit: Expose Unsnapped Dimensions (#1811) Summary: Pull Request resolved: https://github.com/facebook/yoga/pull/1811 X-link: https://github.com/facebook/react-native/pull/51298 ## Resubmit This was backed out due to being up the stack from another change that was backed out, but should be safe by itself. ## Original We want to know if an artifact created during measurement can fully be reused after final layout, but the final layout is allowed to be slightly larger due to pixel grid rounding (while still allowing reuse). It's hard to tell after the fact, whether it is larger because of this rounding (though the measure is used), or if it may be a pixel larger for valid reasons. We can expose the unsnapped dimensions of a node to give us this information, and to correlate measurement artifacts. This is most of the time the same as the layout's measured dimension, though I don't think it's safe to use this, since anything else measuring the node after could clobber this (I think `YGNodeLayoutGetOverflow` may also be prone to this as a bug). Changelog: [Internal] Reviewed By: joevilches Differential Revision: D74673119 fbshipit-source-id: 06d2eb21e28b76458ec88f4dfcaec809707d0390 --- tests/YGRoundingFunctionTest.cpp | 20 ++++++++++++++++++++ yoga/YGNodeLayout.cpp | 8 ++++++++ yoga/YGNodeLayout.h | 10 ++++++++++ yoga/algorithm/PixelGrid.cpp | 12 ++++++------ yoga/node/LayoutResults.h | 9 +++++++++ yoga/node/Node.cpp | 1 + 6 files changed, 54 insertions(+), 6 deletions(-) diff --git a/tests/YGRoundingFunctionTest.cpp b/tests/YGRoundingFunctionTest.cpp index 55b5e86d..47efcbc4 100644 --- a/tests/YGRoundingFunctionTest.cpp +++ b/tests/YGRoundingFunctionTest.cpp @@ -161,3 +161,23 @@ TEST(YogaTest, per_node_point_scale_factor) { YGConfigFree(config2); YGConfigFree(config3); } + +TEST(YogaTest, raw_layout_dimensions) { + YGConfigRef config = YGConfigNew(); + YGConfigSetPointScaleFactor(config, 0.5f); + + YGNodeRef root = YGNodeNewWithConfig(config); + YGNodeStyleSetWidth(root, 11.5f); + YGNodeStyleSetHeight(root, 9.5f); + + YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR); + + ASSERT_EQ(YGNodeLayoutGetWidth(root), 12.0f); + ASSERT_EQ(YGNodeLayoutGetHeight(root), 10.0f); + ASSERT_EQ(YGNodeLayoutGetRawWidth(root), 11.5f); + ASSERT_EQ(YGNodeLayoutGetRawHeight(root), 9.5f); + + YGNodeFreeRecursive(root); + + YGConfigFree(config); +} diff --git a/yoga/YGNodeLayout.cpp b/yoga/YGNodeLayout.cpp index 93fcf0ad..50c8766e 100644 --- a/yoga/YGNodeLayout.cpp +++ b/yoga/YGNodeLayout.cpp @@ -90,3 +90,11 @@ float YGNodeLayoutGetPadding(YGNodeConstRef node, YGEdge edge) { return getResolvedLayoutProperty<&LayoutResults::padding>( node, scopedEnum(edge)); } + +float YGNodeLayoutGetRawHeight(YGNodeConstRef node) { + return resolveRef(node)->getLayout().rawDimension(Dimension::Height); +} + +float YGNodeLayoutGetRawWidth(YGNodeConstRef node) { + return resolveRef(node)->getLayout().rawDimension(Dimension::Width); +} diff --git a/yoga/YGNodeLayout.h b/yoga/YGNodeLayout.h index 02ead588..4f25af21 100644 --- a/yoga/YGNodeLayout.h +++ b/yoga/YGNodeLayout.h @@ -32,4 +32,14 @@ YG_EXPORT float YGNodeLayoutGetMargin(YGNodeConstRef node, YGEdge edge); YG_EXPORT float YGNodeLayoutGetBorder(YGNodeConstRef node, YGEdge edge); YG_EXPORT float YGNodeLayoutGetPadding(YGNodeConstRef node, YGEdge edge); +/** + * Return the measured height of the node, before layout rounding + */ +YG_EXPORT float YGNodeLayoutGetRawHeight(YGNodeConstRef node); + +/** + * Return the measured width of the node, before layout rounding + */ +YG_EXPORT float YGNodeLayoutGetRawWidth(YGNodeConstRef node); + YG_EXTERN_C_END diff --git a/yoga/algorithm/PixelGrid.cpp b/yoga/algorithm/PixelGrid.cpp index 6083f0f2..61de2be2 100644 --- a/yoga/algorithm/PixelGrid.cpp +++ b/yoga/algorithm/PixelGrid.cpp @@ -106,25 +106,25 @@ void roundLayoutResultsToPixelGrid( const bool hasFractionalHeight = !yoga::inexactEquals(round(scaledNodeHeight), scaledNodeHeight); - node->setLayoutDimension( + node->getLayout().setDimension( + Dimension::Width, roundValueToPixelGrid( absoluteNodeRight, pointScaleFactor, (textRounding && hasFractionalWidth), (textRounding && !hasFractionalWidth)) - roundValueToPixelGrid( - absoluteNodeLeft, pointScaleFactor, false, textRounding), - Dimension::Width); + absoluteNodeLeft, pointScaleFactor, false, textRounding)); - node->setLayoutDimension( + node->getLayout().setDimension( + Dimension::Height, roundValueToPixelGrid( absoluteNodeBottom, pointScaleFactor, (textRounding && hasFractionalHeight), (textRounding && !hasFractionalHeight)) - roundValueToPixelGrid( - absoluteNodeTop, pointScaleFactor, false, textRounding), - Dimension::Height); + absoluteNodeTop, pointScaleFactor, false, textRounding)); } for (yoga::Node* child : node->getChildren()) { diff --git a/yoga/node/LayoutResults.h b/yoga/node/LayoutResults.h index 9f0aeaf7..6776a423 100644 --- a/yoga/node/LayoutResults.h +++ b/yoga/node/LayoutResults.h @@ -66,10 +66,18 @@ struct LayoutResults { return measuredDimensions_[yoga::to_underlying(axis)]; } + float rawDimension(Dimension axis) const { + return rawDimensions_[yoga::to_underlying(axis)]; + } + void setMeasuredDimension(Dimension axis, float dimension) { measuredDimensions_[yoga::to_underlying(axis)] = dimension; } + void setRawDimension(Dimension axis, float dimension) { + rawDimensions_[yoga::to_underlying(axis)] = dimension; + } + float position(PhysicalEdge physicalEdge) const { return position_[yoga::to_underlying(physicalEdge)]; } @@ -113,6 +121,7 @@ struct LayoutResults { std::array dimensions_ = {{YGUndefined, YGUndefined}}; std::array measuredDimensions_ = {{YGUndefined, YGUndefined}}; + std::array rawDimensions_ = {{YGUndefined, YGUndefined}}; std::array position_ = {}; std::array margin_ = {}; std::array border_ = {}; diff --git a/yoga/node/Node.cpp b/yoga/node/Node.cpp index dce42fb1..fbdf5c1b 100644 --- a/yoga/node/Node.cpp +++ b/yoga/node/Node.cpp @@ -247,6 +247,7 @@ void Node::setLayoutHadOverflow(bool hadOverflow) { void Node::setLayoutDimension(float lengthValue, Dimension dimension) { layout_.setDimension(dimension, lengthValue); + layout_.setRawDimension(dimension, lengthValue); } // If both left and right are defined, then use left. Otherwise return +left or -- 2.50.1.windows.1 From 123276157121f8d87d1245f94cf5f87edeeb18b6 Mon Sep 17 00:00:00 2001 From: Nick Gerleman Date: Mon, 2 Jun 2025 19:32:45 -0700 Subject: [PATCH 06/32] YGPersistentNodeCloningTest (#1813) Summary: Pull Request resolved: https://github.com/facebook/yoga/pull/1813 This adds a unit test to Yoga, which emulates the model of "persistent Yoga nodes" and cloning used by React Fabric, including the private (but relied on) Yoga APIs. It models the over-invalidation exposed in D75287261, which reproduces (due to Yoga incorrectly measuring flex-basis under fit-content, and that constraint changing when sibling changes) but this test for now sets a definite height on A, to show that we only clone what is neccesary, when measure constraints do not have to change. Having a minimal version of Fabric's model in Yoga unit tests should make some of these interesting interactions a bit easier to debug. Changelog: [Internal] Reviewed By: javache Differential Revision: D75572762 fbshipit-source-id: cda8b3fdd6e538a55dd100494518688c864bd233 --- tests/YGPersistentNodeCloningTest.cpp | 184 ++++++++++++++++++++++++++ 1 file changed, 184 insertions(+) create mode 100644 tests/YGPersistentNodeCloningTest.cpp diff --git a/tests/YGPersistentNodeCloningTest.cpp b/tests/YGPersistentNodeCloningTest.cpp new file mode 100644 index 00000000..137da26c --- /dev/null +++ b/tests/YGPersistentNodeCloningTest.cpp @@ -0,0 +1,184 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include +#include +#include +#include + +#include +#include +#include + +namespace facebook::yoga { + +struct YGPersistentNodeCloningTest : public ::testing::Test { + struct NodeWrapper { + explicit NodeWrapper( + YGConfigRef config, + std::vector> children = {}) + : node{YGNodeNewWithConfig(config)}, children{std::move(children)} { + YGNodeSetContext(node, this); + + auto privateNode = resolveRef(node); + for (const auto& child : this->children) { + auto privateChild = resolveRef(child->node); + // Claim first ownership of not yet owned nodes, to avoid immediately + // cloning them + if (YGNodeGetOwner(child->node) == nullptr) { + privateChild->setOwner(privateNode); + } + privateNode->insertChild(privateChild, privateNode->getChildCount()); + } + } + + // Clone, with current children, for mutation + NodeWrapper(const NodeWrapper& other) + : node{YGNodeClone(other.node)}, children{other.children} { + YGNodeSetContext(node, this); + + auto privateNode = resolveRef(node); + privateNode->setOwner(nullptr); + } + + // Clone, with new children + NodeWrapper( + const NodeWrapper& other, + std::vector> children) + : node{YGNodeClone(other.node)}, children{std::move(children)} { + YGNodeSetContext(node, this); + + auto privateNode = resolveRef(node); + privateNode->setOwner(nullptr); + privateNode->setChildren({}); + privateNode->setDirty(true); + + for (const auto& child : this->children) { + auto privateChild = resolveRef(child->node); + // Claim first ownership of not yet owned nodes, to avoid immediately + // cloning them + if (YGNodeGetOwner(child->node) == nullptr) { + privateChild->setOwner(privateNode); + } + privateNode->insertChild(privateChild, privateNode->getChildCount()); + } + } + + NodeWrapper(NodeWrapper&&) = delete; + + ~NodeWrapper() { + YGNodeFree(node); + } + + NodeWrapper& operator=(const NodeWrapper& other) = delete; + NodeWrapper& operator=(NodeWrapper&& other) = delete; + + YGNodeRef node; + std::vector> children; + }; + + struct ConfigWrapper { + ConfigWrapper() { + YGConfigSetCloneNodeFunc( + config, + [](YGNodeConstRef oldNode, YGNodeConstRef owner, size_t childIndex) { + onClone(oldNode, owner, childIndex); + auto wrapper = static_cast(YGNodeGetContext(owner)); + auto old = static_cast(YGNodeGetContext(oldNode)); + + wrapper->children[childIndex] = std::make_shared(*old); + return wrapper->children[childIndex]->node; + }); + } + + ConfigWrapper(const ConfigWrapper&) = delete; + ConfigWrapper(ConfigWrapper&&) = delete; + + ~ConfigWrapper() { + YGConfigFree(config); + } + + ConfigWrapper& operator=(const ConfigWrapper&) = delete; + ConfigWrapper& operator=(ConfigWrapper&&) = delete; + + YGConfigRef config{YGConfigNew()}; + }; + + ConfigWrapper configWrapper; + YGConfigRef config{configWrapper.config}; + + void SetUp() override { + onClone = [](...) {}; + } + + // NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables) + static inline std::function + onClone; +}; + +TEST_F( + YGPersistentNodeCloningTest, + changing_sibling_height_does_not_clone_neighbors) { + // + // + // + // + // + // + // + // + // + // + + auto sibling = std::make_shared(config); + YGNodeStyleSetHeight(sibling->node, 1); + + auto d = std::make_shared(config); + auto c = std::make_shared(config, std::vector{d}); + auto b = std::make_shared(config, std::vector{c}); + auto a = std::make_shared(config, std::vector{b}); + YGNodeStyleSetHeight(a->node, 1); + + auto scrollContentView = + std::make_shared(config, std::vector{sibling, a}); + YGNodeStyleSetPositionType(scrollContentView->node, YGPositionTypeAbsolute); + + auto scrollView = + std::make_shared(config, std::vector{scrollContentView}); + YGNodeStyleSetWidth(scrollView->node, 100); + YGNodeStyleSetHeight(scrollView->node, 100); + + // We don't expect any cloning during the first layout + onClone = [](...) { FAIL(); }; + + YGNodeCalculateLayout( + scrollView->node, YGUndefined, YGUndefined, YGDirectionLTR); + + auto siblingPrime = std::make_shared(config); + YGNodeStyleSetHeight(siblingPrime->node, 2); + + auto scrollContentViewPrime = std::make_shared( + *scrollContentView, std::vector{siblingPrime, a}); + auto scrollViewPrime = std::make_shared( + *scrollView, std::vector{scrollContentViewPrime}); + + std::vector nodesCloned; + // We should only need to clone "A" + onClone = [&](YGNodeConstRef oldNode, + YGNodeConstRef /*owner*/, + size_t /*childIndex*/) { + nodesCloned.push_back(static_cast(YGNodeGetContext(oldNode))); + }; + + YGNodeCalculateLayout( + scrollViewPrime->node, YGUndefined, YGUndefined, YGDirectionLTR); + + EXPECT_EQ(nodesCloned.size(), 1); + EXPECT_EQ(nodesCloned[0], a.get()); +} + +} // namespace facebook::yoga -- 2.50.1.windows.1 From 073c1361170322c72521f981115a66b546c87235 Mon Sep 17 00:00:00 2001 From: Nicola Corti Date: Wed, 11 Jun 2025 11:46:34 -0700 Subject: [PATCH 07/32] Remove unnecessary gradle-enterprise.gradle.kts from Yoga (#1817) Summary: Pull Request resolved: https://github.com/facebook/yoga/pull/1817 This file is not really necessary. As we don't have a Gradle Enterprise instance anymore, let's just remove it and inline it. Reviewed By: mdvacca Differential Revision: D76436236 fbshipit-source-id: 27fcc48574905415b147f67dd4a8f57dffbeda3e --- gradle/gradle-enterprise.gradle.kts.sample | 17 ----------------- settings.gradle.kts | 13 +++++++------ 2 files changed, 7 insertions(+), 23 deletions(-) delete mode 100644 gradle/gradle-enterprise.gradle.kts.sample diff --git a/gradle/gradle-enterprise.gradle.kts.sample b/gradle/gradle-enterprise.gradle.kts.sample deleted file mode 100644 index 91940e25..00000000 --- a/gradle/gradle-enterprise.gradle.kts.sample +++ /dev/null @@ -1,17 +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. - */ - -// You can use this script to configure the gradleEnterprise{} block in your build. -// You need to rename this file to ./gradle/gradle-enterprise.gradle.kts in order for -// this to be processed. -extensions.getByName("gradleEnterprise").withGroovyBuilder { - setProperty("server", "https://your-gradle-enterprise-instance.example.com") - getProperty("buildScan").withGroovyBuilder { - "publishAlways"() - "tag"(if(System.getenv("CI") != null) "CI" else "Local") - } -} diff --git a/settings.gradle.kts b/settings.gradle.kts index c6952ca2..3be83568 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -19,10 +19,11 @@ include(":yoga") project(":yoga").projectDir = file("java") -rootProject.name = "yoga-github" - -// If you specify a file inside gradle/gradle-enterprise.gradle.kts -// you can configure your custom Gradle Enterprise instance -if (file("./gradle/gradle-enterprise.gradle.kts").exists()) { - apply(from = "./gradle/gradle-enterprise.gradle.kts") +gradleEnterprise { + buildScan { + termsOfServiceUrl = "https://gradle.com/terms-of-service" + termsOfServiceAgree = "yes" + } } + +rootProject.name = "yoga-github" -- 2.50.1.windows.1 From 117fa494f7a873f53d3d27537417d82d8d76ab72 Mon Sep 17 00:00:00 2001 From: Nicola Corti Date: Wed, 11 Jun 2025 16:12:06 -0700 Subject: [PATCH 08/32] Migrate from OSSRH to Central Portal (#1816) Summary: Pull Request resolved: https://github.com/facebook/yoga/pull/1816 This migrates Yoga to publish to Central Portal rather than OSSRC Reviewed By: NickGerleman Differential Revision: D76436235 fbshipit-source-id: ddaaa95472054aa2b09399b5cc8d821dae51234f --- build.gradle | 2 ++ 1 file changed, 2 insertions(+) diff --git a/build.gradle b/build.gradle index 3dec0644..6352e5c9 100644 --- a/build.gradle +++ b/build.gradle @@ -34,6 +34,8 @@ nexusPublishing { sonatype { username.set(sonatypeUsername) password.set(sonatypePassword) + nexusUrl.set(uri("https://ossrh-staging-api.central.sonatype.com/service/local/")) + snapshotRepositoryUrl.set(uri("https://central.sonatype.com/repository/maven-snapshots/")) } } } -- 2.50.1.windows.1 From 27d632c697e983d15f14fc4b9c3adf35c0ade680 Mon Sep 17 00:00:00 2001 From: Nick Gerleman Date: Tue, 17 Jun 2025 12:15:55 -0700 Subject: [PATCH 09/32] 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 --- gentest/fixtures/YGAlignItemsTest.html | 11 +++ .../com/facebook/yoga/YGAlignItemsTest.java | 82 ++++++++++++++++- .../tests/generated/YGAlignItemsTest.test.ts | 87 ++++++++++++++++++- tests/generated/YGAlignItemsTest.cpp | 83 +++++++++++++++++- yoga/algorithm/CalculateLayout.cpp | 14 +-- 5 files changed, 268 insertions(+), 9 deletions(-) diff --git a/gentest/fixtures/YGAlignItemsTest.html b/gentest/fixtures/YGAlignItemsTest.html index c3e6af41..6b50772a 100644 --- a/gentest/fixtures/YGAlignItemsTest.html +++ b/gentest/fixtures/YGAlignItemsTest.html @@ -240,3 +240,14 @@
+ +
+
+
+
+
+
+
+
+
diff --git a/java/tests/generated/com/facebook/yoga/YGAlignItemsTest.java b/java/tests/generated/com/facebook/yoga/YGAlignItemsTest.java index a5be942b..8a32201d 100644 --- a/java/tests/generated/com/facebook/yoga/YGAlignItemsTest.java +++ b/java/tests/generated/com/facebook/yoga/YGAlignItemsTest.java @@ -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<> + * @generated SignedSource<<84597dd8b2c4f3aac1f21abe68f25308>> * generated by gentest/gentest-driver.ts from gentest/fixtures/YGAlignItemsTest.html */ @@ -2293,6 +2293,86 @@ public class YGAlignItemsTest { assertEquals(50f, root_child1.getLayoutHeight(), 0.0f); } + @Test + public void test_align_items_non_stretch_s526008() { + YogaConfig config = YogaConfigFactory.create(); + + final YogaNode root = createNode(config); + root.setPositionType(YogaPositionType.ABSOLUTE); + root.setWidth(400f); + root.setHeight(400f); + + final YogaNode root_child0 = createNode(config); + root_child0.setFlexDirection(YogaFlexDirection.ROW); + root.addChildAt(root_child0, 0); + + final YogaNode root_child0_child0 = createNode(config); + root_child0_child0.setAlignItems(YogaAlign.FLEX_START); + root_child0.addChildAt(root_child0_child0, 0); + + final YogaNode root_child0_child0_child0 = createNode(config); + root_child0_child0.addChildAt(root_child0_child0_child0, 0); + + final YogaNode root_child0_child0_child0_child0 = createNode(config); + root_child0_child0_child0_child0.setHeight(10f); + root_child0_child0_child0.addChildAt(root_child0_child0_child0_child0, 0); + root.setDirection(YogaDirection.LTR); + root.calculateLayout(YogaConstants.UNDEFINED, YogaConstants.UNDEFINED); + + assertEquals(0f, root.getLayoutX(), 0.0f); + assertEquals(0f, root.getLayoutY(), 0.0f); + assertEquals(400f, root.getLayoutWidth(), 0.0f); + assertEquals(400f, root.getLayoutHeight(), 0.0f); + + assertEquals(0f, root_child0.getLayoutX(), 0.0f); + assertEquals(0f, root_child0.getLayoutY(), 0.0f); + assertEquals(400f, root_child0.getLayoutWidth(), 0.0f); + assertEquals(10f, root_child0.getLayoutHeight(), 0.0f); + + assertEquals(0f, root_child0_child0.getLayoutX(), 0.0f); + assertEquals(0f, root_child0_child0.getLayoutY(), 0.0f); + assertEquals(0f, root_child0_child0.getLayoutWidth(), 0.0f); + assertEquals(10f, root_child0_child0.getLayoutHeight(), 0.0f); + + assertEquals(0f, root_child0_child0_child0.getLayoutX(), 0.0f); + assertEquals(0f, root_child0_child0_child0.getLayoutY(), 0.0f); + assertEquals(0f, root_child0_child0_child0.getLayoutWidth(), 0.0f); + assertEquals(10f, root_child0_child0_child0.getLayoutHeight(), 0.0f); + + assertEquals(0f, root_child0_child0_child0_child0.getLayoutX(), 0.0f); + assertEquals(0f, root_child0_child0_child0_child0.getLayoutY(), 0.0f); + assertEquals(0f, root_child0_child0_child0_child0.getLayoutWidth(), 0.0f); + assertEquals(10f, root_child0_child0_child0_child0.getLayoutHeight(), 0.0f); + + root.setDirection(YogaDirection.RTL); + root.calculateLayout(YogaConstants.UNDEFINED, YogaConstants.UNDEFINED); + + assertEquals(0f, root.getLayoutX(), 0.0f); + assertEquals(0f, root.getLayoutY(), 0.0f); + assertEquals(400f, root.getLayoutWidth(), 0.0f); + assertEquals(400f, root.getLayoutHeight(), 0.0f); + + assertEquals(0f, root_child0.getLayoutX(), 0.0f); + assertEquals(0f, root_child0.getLayoutY(), 0.0f); + assertEquals(400f, root_child0.getLayoutWidth(), 0.0f); + assertEquals(10f, root_child0.getLayoutHeight(), 0.0f); + + assertEquals(400f, root_child0_child0.getLayoutX(), 0.0f); + assertEquals(0f, root_child0_child0.getLayoutY(), 0.0f); + assertEquals(0f, root_child0_child0.getLayoutWidth(), 0.0f); + assertEquals(10f, root_child0_child0.getLayoutHeight(), 0.0f); + + assertEquals(0f, root_child0_child0_child0.getLayoutX(), 0.0f); + assertEquals(0f, root_child0_child0_child0.getLayoutY(), 0.0f); + assertEquals(0f, root_child0_child0_child0.getLayoutWidth(), 0.0f); + assertEquals(10f, root_child0_child0_child0.getLayoutHeight(), 0.0f); + + assertEquals(0f, root_child0_child0_child0_child0.getLayoutX(), 0.0f); + assertEquals(0f, root_child0_child0_child0_child0.getLayoutY(), 0.0f); + assertEquals(0f, root_child0_child0_child0_child0.getLayoutWidth(), 0.0f); + assertEquals(10f, root_child0_child0_child0_child0.getLayoutHeight(), 0.0f); + } + private YogaNode createNode(YogaConfig config) { return mNodeFactory.create(config); } diff --git a/javascript/tests/generated/YGAlignItemsTest.test.ts b/javascript/tests/generated/YGAlignItemsTest.test.ts index 39c013a3..ae4dc635 100644 --- a/javascript/tests/generated/YGAlignItemsTest.test.ts +++ b/javascript/tests/generated/YGAlignItemsTest.test.ts @@ -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<> * 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(); + } +}); diff --git a/tests/generated/YGAlignItemsTest.cpp b/tests/generated/YGAlignItemsTest.cpp index 4a4f48ec..e64d68e4 100644 --- a/tests/generated/YGAlignItemsTest.cpp +++ b/tests/generated/YGAlignItemsTest.cpp @@ -5,7 +5,7 @@ * LICENSE file in the root directory of this source tree. * * clang-format off - * @generated SignedSource<<71295a398c89ea424490884a05e2c77c>> + * @generated SignedSource<<1db57b05babb408c08efcec7dbdf16fb>> * generated by gentest/gentest-driver.ts from gentest/fixtures/YGAlignItemsTest.html */ @@ -2310,3 +2310,84 @@ TEST(YogaTest, align_stretch_with_row_reverse) { YGConfigFree(config); } + +TEST(YogaTest, align_items_non_stretch_s526008) { + YGConfigRef config = YGConfigNew(); + + YGNodeRef root = YGNodeNewWithConfig(config); + YGNodeStyleSetPositionType(root, YGPositionTypeAbsolute); + YGNodeStyleSetWidth(root, 400); + YGNodeStyleSetHeight(root, 400); + + YGNodeRef root_child0 = YGNodeNewWithConfig(config); + YGNodeStyleSetFlexDirection(root_child0, YGFlexDirectionRow); + YGNodeInsertChild(root, root_child0, 0); + + YGNodeRef root_child0_child0 = YGNodeNewWithConfig(config); + YGNodeStyleSetAlignItems(root_child0_child0, YGAlignFlexStart); + YGNodeInsertChild(root_child0, root_child0_child0, 0); + + YGNodeRef root_child0_child0_child0 = YGNodeNewWithConfig(config); + YGNodeInsertChild(root_child0_child0, root_child0_child0_child0, 0); + + YGNodeRef root_child0_child0_child0_child0 = YGNodeNewWithConfig(config); + YGNodeStyleSetHeight(root_child0_child0_child0_child0, 10); + YGNodeInsertChild(root_child0_child0_child0, root_child0_child0_child0_child0, 0); + YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR); + + ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root)); + ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root)); + ASSERT_FLOAT_EQ(400, YGNodeLayoutGetWidth(root)); + ASSERT_FLOAT_EQ(400, YGNodeLayoutGetHeight(root)); + + ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0)); + ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0)); + ASSERT_FLOAT_EQ(400, YGNodeLayoutGetWidth(root_child0)); + ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child0)); + + ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0_child0)); + ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0_child0)); + ASSERT_FLOAT_EQ(0, YGNodeLayoutGetWidth(root_child0_child0)); + ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child0_child0)); + + ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0_child0_child0)); + ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0_child0_child0)); + ASSERT_FLOAT_EQ(0, YGNodeLayoutGetWidth(root_child0_child0_child0)); + ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child0_child0_child0)); + + ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0_child0_child0_child0)); + ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0_child0_child0_child0)); + ASSERT_FLOAT_EQ(0, YGNodeLayoutGetWidth(root_child0_child0_child0_child0)); + ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child0_child0_child0_child0)); + + YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL); + + ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root)); + ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root)); + ASSERT_FLOAT_EQ(400, YGNodeLayoutGetWidth(root)); + ASSERT_FLOAT_EQ(400, YGNodeLayoutGetHeight(root)); + + ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0)); + ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0)); + ASSERT_FLOAT_EQ(400, YGNodeLayoutGetWidth(root_child0)); + ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child0)); + + ASSERT_FLOAT_EQ(400, YGNodeLayoutGetLeft(root_child0_child0)); + ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0_child0)); + ASSERT_FLOAT_EQ(0, YGNodeLayoutGetWidth(root_child0_child0)); + ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child0_child0)); + + ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0_child0_child0)); + ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0_child0_child0)); + ASSERT_FLOAT_EQ(0, YGNodeLayoutGetWidth(root_child0_child0_child0)); + ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child0_child0_child0)); + + ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0_child0_child0_child0)); + ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0_child0_child0_child0)); + ASSERT_FLOAT_EQ(0, YGNodeLayoutGetWidth(root_child0_child0_child0_child0)); + ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child0_child0_child0_child0)); + + YGNodeFreeRecursive(root); + + YGConfigFree(config); +} diff --git a/yoga/algorithm/CalculateLayout.cpp b/yoga/algorithm/CalculateLayout.cpp index 36184745..bdc75fa8 100644 --- a/yoga/algorithm/CalculateLayout.cpp +++ b/yoga/algorithm/CalculateLayout.cpp @@ -415,6 +415,12 @@ static void measureNodeWithoutChildren( Dimension::Height); } +inline bool isFixedSize(float dim, SizingMode sizingMode) { + return yoga::isDefined(dim) && + (sizingMode == SizingMode::StretchFit || + (sizingMode == SizingMode::FitContent && dim <= 0.0)); +} + static bool measureNodeWithFixedSize( yoga::Node* const node, const Direction direction, @@ -424,12 +430,8 @@ static bool measureNodeWithFixedSize( const SizingMode heightSizingMode, const float ownerWidth, const float ownerHeight) { - if ((yoga::isDefined(availableWidth) && - widthSizingMode == SizingMode::FitContent && availableWidth <= 0.0f) || - (yoga::isDefined(availableHeight) && - heightSizingMode == SizingMode::FitContent && availableHeight <= 0.0f) || - (widthSizingMode == SizingMode::StretchFit && - heightSizingMode == SizingMode::StretchFit)) { + if (isFixedSize(availableWidth, widthSizingMode) && + isFixedSize(availableHeight, heightSizingMode)) { node->setLayoutMeasuredDimension( boundAxis( node, -- 2.50.1.windows.1 From 30291398f36fd2627f8276f74e8e30f663878dac Mon Sep 17 00:00:00 2001 From: FBLite Revert Bot Date: Tue, 17 Jun 2025 14:33:32 -0700 Subject: [PATCH 10/32] Revert D76793705: Fix possible invalid measurements when width or height is zero pixels Differential Revision: D76793705 Original commit changeset: ea4c00e68891 Original Phabricator Diff: D76793705 fbshipit-source-id: 95d6b66ab08e073da9fb07fd4094a7e30e2f453b --- gentest/fixtures/YGAlignItemsTest.html | 11 --- .../com/facebook/yoga/YGAlignItemsTest.java | 82 +---------------- .../tests/generated/YGAlignItemsTest.test.ts | 87 +------------------ tests/generated/YGAlignItemsTest.cpp | 83 +----------------- yoga/algorithm/CalculateLayout.cpp | 14 ++- 5 files changed, 9 insertions(+), 268 deletions(-) diff --git a/gentest/fixtures/YGAlignItemsTest.html b/gentest/fixtures/YGAlignItemsTest.html index 6b50772a..c3e6af41 100644 --- a/gentest/fixtures/YGAlignItemsTest.html +++ b/gentest/fixtures/YGAlignItemsTest.html @@ -240,14 +240,3 @@
- -
-
-
-
-
-
-
-
-
diff --git a/java/tests/generated/com/facebook/yoga/YGAlignItemsTest.java b/java/tests/generated/com/facebook/yoga/YGAlignItemsTest.java index 8a32201d..a5be942b 100644 --- a/java/tests/generated/com/facebook/yoga/YGAlignItemsTest.java +++ b/java/tests/generated/com/facebook/yoga/YGAlignItemsTest.java @@ -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<<84597dd8b2c4f3aac1f21abe68f25308>> + * @generated SignedSource<> * generated by gentest/gentest-driver.ts from gentest/fixtures/YGAlignItemsTest.html */ @@ -2293,86 +2293,6 @@ public class YGAlignItemsTest { assertEquals(50f, root_child1.getLayoutHeight(), 0.0f); } - @Test - public void test_align_items_non_stretch_s526008() { - YogaConfig config = YogaConfigFactory.create(); - - final YogaNode root = createNode(config); - root.setPositionType(YogaPositionType.ABSOLUTE); - root.setWidth(400f); - root.setHeight(400f); - - final YogaNode root_child0 = createNode(config); - root_child0.setFlexDirection(YogaFlexDirection.ROW); - root.addChildAt(root_child0, 0); - - final YogaNode root_child0_child0 = createNode(config); - root_child0_child0.setAlignItems(YogaAlign.FLEX_START); - root_child0.addChildAt(root_child0_child0, 0); - - final YogaNode root_child0_child0_child0 = createNode(config); - root_child0_child0.addChildAt(root_child0_child0_child0, 0); - - final YogaNode root_child0_child0_child0_child0 = createNode(config); - root_child0_child0_child0_child0.setHeight(10f); - root_child0_child0_child0.addChildAt(root_child0_child0_child0_child0, 0); - root.setDirection(YogaDirection.LTR); - root.calculateLayout(YogaConstants.UNDEFINED, YogaConstants.UNDEFINED); - - assertEquals(0f, root.getLayoutX(), 0.0f); - assertEquals(0f, root.getLayoutY(), 0.0f); - assertEquals(400f, root.getLayoutWidth(), 0.0f); - assertEquals(400f, root.getLayoutHeight(), 0.0f); - - assertEquals(0f, root_child0.getLayoutX(), 0.0f); - assertEquals(0f, root_child0.getLayoutY(), 0.0f); - assertEquals(400f, root_child0.getLayoutWidth(), 0.0f); - assertEquals(10f, root_child0.getLayoutHeight(), 0.0f); - - assertEquals(0f, root_child0_child0.getLayoutX(), 0.0f); - assertEquals(0f, root_child0_child0.getLayoutY(), 0.0f); - assertEquals(0f, root_child0_child0.getLayoutWidth(), 0.0f); - assertEquals(10f, root_child0_child0.getLayoutHeight(), 0.0f); - - assertEquals(0f, root_child0_child0_child0.getLayoutX(), 0.0f); - assertEquals(0f, root_child0_child0_child0.getLayoutY(), 0.0f); - assertEquals(0f, root_child0_child0_child0.getLayoutWidth(), 0.0f); - assertEquals(10f, root_child0_child0_child0.getLayoutHeight(), 0.0f); - - assertEquals(0f, root_child0_child0_child0_child0.getLayoutX(), 0.0f); - assertEquals(0f, root_child0_child0_child0_child0.getLayoutY(), 0.0f); - assertEquals(0f, root_child0_child0_child0_child0.getLayoutWidth(), 0.0f); - assertEquals(10f, root_child0_child0_child0_child0.getLayoutHeight(), 0.0f); - - root.setDirection(YogaDirection.RTL); - root.calculateLayout(YogaConstants.UNDEFINED, YogaConstants.UNDEFINED); - - assertEquals(0f, root.getLayoutX(), 0.0f); - assertEquals(0f, root.getLayoutY(), 0.0f); - assertEquals(400f, root.getLayoutWidth(), 0.0f); - assertEquals(400f, root.getLayoutHeight(), 0.0f); - - assertEquals(0f, root_child0.getLayoutX(), 0.0f); - assertEquals(0f, root_child0.getLayoutY(), 0.0f); - assertEquals(400f, root_child0.getLayoutWidth(), 0.0f); - assertEquals(10f, root_child0.getLayoutHeight(), 0.0f); - - assertEquals(400f, root_child0_child0.getLayoutX(), 0.0f); - assertEquals(0f, root_child0_child0.getLayoutY(), 0.0f); - assertEquals(0f, root_child0_child0.getLayoutWidth(), 0.0f); - assertEquals(10f, root_child0_child0.getLayoutHeight(), 0.0f); - - assertEquals(0f, root_child0_child0_child0.getLayoutX(), 0.0f); - assertEquals(0f, root_child0_child0_child0.getLayoutY(), 0.0f); - assertEquals(0f, root_child0_child0_child0.getLayoutWidth(), 0.0f); - assertEquals(10f, root_child0_child0_child0.getLayoutHeight(), 0.0f); - - assertEquals(0f, root_child0_child0_child0_child0.getLayoutX(), 0.0f); - assertEquals(0f, root_child0_child0_child0_child0.getLayoutY(), 0.0f); - assertEquals(0f, root_child0_child0_child0_child0.getLayoutWidth(), 0.0f); - assertEquals(10f, root_child0_child0_child0_child0.getLayoutHeight(), 0.0f); - } - private YogaNode createNode(YogaConfig config) { return mNodeFactory.create(config); } diff --git a/javascript/tests/generated/YGAlignItemsTest.test.ts b/javascript/tests/generated/YGAlignItemsTest.test.ts index ae4dc635..39c013a3 100644 --- a/javascript/tests/generated/YGAlignItemsTest.test.ts +++ b/javascript/tests/generated/YGAlignItemsTest.test.ts @@ -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<> + * @generated SignedSource<<075a0b67003e5c4a1f51bd99da71c700>> * generated by gentest/gentest-driver.ts from gentest/fixtures/YGAlignItemsTest.html */ @@ -2442,88 +2442,3 @@ 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(); - } -}); diff --git a/tests/generated/YGAlignItemsTest.cpp b/tests/generated/YGAlignItemsTest.cpp index e64d68e4..4a4f48ec 100644 --- a/tests/generated/YGAlignItemsTest.cpp +++ b/tests/generated/YGAlignItemsTest.cpp @@ -5,7 +5,7 @@ * LICENSE file in the root directory of this source tree. * * clang-format off - * @generated SignedSource<<1db57b05babb408c08efcec7dbdf16fb>> + * @generated SignedSource<<71295a398c89ea424490884a05e2c77c>> * generated by gentest/gentest-driver.ts from gentest/fixtures/YGAlignItemsTest.html */ @@ -2310,84 +2310,3 @@ TEST(YogaTest, align_stretch_with_row_reverse) { YGConfigFree(config); } - -TEST(YogaTest, align_items_non_stretch_s526008) { - YGConfigRef config = YGConfigNew(); - - YGNodeRef root = YGNodeNewWithConfig(config); - YGNodeStyleSetPositionType(root, YGPositionTypeAbsolute); - YGNodeStyleSetWidth(root, 400); - YGNodeStyleSetHeight(root, 400); - - YGNodeRef root_child0 = YGNodeNewWithConfig(config); - YGNodeStyleSetFlexDirection(root_child0, YGFlexDirectionRow); - YGNodeInsertChild(root, root_child0, 0); - - YGNodeRef root_child0_child0 = YGNodeNewWithConfig(config); - YGNodeStyleSetAlignItems(root_child0_child0, YGAlignFlexStart); - YGNodeInsertChild(root_child0, root_child0_child0, 0); - - YGNodeRef root_child0_child0_child0 = YGNodeNewWithConfig(config); - YGNodeInsertChild(root_child0_child0, root_child0_child0_child0, 0); - - YGNodeRef root_child0_child0_child0_child0 = YGNodeNewWithConfig(config); - YGNodeStyleSetHeight(root_child0_child0_child0_child0, 10); - YGNodeInsertChild(root_child0_child0_child0, root_child0_child0_child0_child0, 0); - YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR); - - ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root)); - ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root)); - ASSERT_FLOAT_EQ(400, YGNodeLayoutGetWidth(root)); - ASSERT_FLOAT_EQ(400, YGNodeLayoutGetHeight(root)); - - ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0)); - ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0)); - ASSERT_FLOAT_EQ(400, YGNodeLayoutGetWidth(root_child0)); - ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child0)); - - ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0_child0)); - ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0_child0)); - ASSERT_FLOAT_EQ(0, YGNodeLayoutGetWidth(root_child0_child0)); - ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child0_child0)); - - ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0_child0_child0)); - ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0_child0_child0)); - ASSERT_FLOAT_EQ(0, YGNodeLayoutGetWidth(root_child0_child0_child0)); - ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child0_child0_child0)); - - ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0_child0_child0_child0)); - ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0_child0_child0_child0)); - ASSERT_FLOAT_EQ(0, YGNodeLayoutGetWidth(root_child0_child0_child0_child0)); - ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child0_child0_child0_child0)); - - YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL); - - ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root)); - ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root)); - ASSERT_FLOAT_EQ(400, YGNodeLayoutGetWidth(root)); - ASSERT_FLOAT_EQ(400, YGNodeLayoutGetHeight(root)); - - ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0)); - ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0)); - ASSERT_FLOAT_EQ(400, YGNodeLayoutGetWidth(root_child0)); - ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child0)); - - ASSERT_FLOAT_EQ(400, YGNodeLayoutGetLeft(root_child0_child0)); - ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0_child0)); - ASSERT_FLOAT_EQ(0, YGNodeLayoutGetWidth(root_child0_child0)); - ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child0_child0)); - - ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0_child0_child0)); - ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0_child0_child0)); - ASSERT_FLOAT_EQ(0, YGNodeLayoutGetWidth(root_child0_child0_child0)); - ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child0_child0_child0)); - - ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0_child0_child0_child0)); - ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0_child0_child0_child0)); - ASSERT_FLOAT_EQ(0, YGNodeLayoutGetWidth(root_child0_child0_child0_child0)); - ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child0_child0_child0_child0)); - - YGNodeFreeRecursive(root); - - YGConfigFree(config); -} diff --git a/yoga/algorithm/CalculateLayout.cpp b/yoga/algorithm/CalculateLayout.cpp index bdc75fa8..36184745 100644 --- a/yoga/algorithm/CalculateLayout.cpp +++ b/yoga/algorithm/CalculateLayout.cpp @@ -415,12 +415,6 @@ static void measureNodeWithoutChildren( Dimension::Height); } -inline bool isFixedSize(float dim, SizingMode sizingMode) { - return yoga::isDefined(dim) && - (sizingMode == SizingMode::StretchFit || - (sizingMode == SizingMode::FitContent && dim <= 0.0)); -} - static bool measureNodeWithFixedSize( yoga::Node* const node, const Direction direction, @@ -430,8 +424,12 @@ static bool measureNodeWithFixedSize( const SizingMode heightSizingMode, const float ownerWidth, const float ownerHeight) { - if (isFixedSize(availableWidth, widthSizingMode) && - isFixedSize(availableHeight, heightSizingMode)) { + if ((yoga::isDefined(availableWidth) && + widthSizingMode == SizingMode::FitContent && availableWidth <= 0.0f) || + (yoga::isDefined(availableHeight) && + heightSizingMode == SizingMode::FitContent && availableHeight <= 0.0f) || + (widthSizingMode == SizingMode::StretchFit && + heightSizingMode == SizingMode::StretchFit)) { node->setLayoutMeasuredDimension( boundAxis( node, -- 2.50.1.windows.1 From 4b5ca501176c1cb59a6cdca731da4fb62edb736f Mon Sep 17 00:00:00 2001 From: Nick Gerleman Date: Mon, 30 Jun 2025 20:46:39 -0700 Subject: [PATCH 11/32] Reland Fix possible invalid measurements when width or height is zero pixels (#1823) Summary: Pull Request resolved: https://github.com/facebook/yoga/pull/1823 X-link: https://github.com/facebook/react-native/pull/52348 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: D76851589 fbshipit-source-id: 6f5a0e6beccc51f591726c9e83e9b90f3350ed0f --- gentest/fixtures/YGAlignItemsTest.html | 11 +++ .../com/facebook/yoga/YGAlignItemsTest.java | 82 ++++++++++++++++- .../tests/generated/YGAlignItemsTest.test.ts | 87 ++++++++++++++++++- tests/generated/YGAlignItemsTest.cpp | 83 +++++++++++++++++- yoga/algorithm/CalculateLayout.cpp | 14 +-- 5 files changed, 268 insertions(+), 9 deletions(-) diff --git a/gentest/fixtures/YGAlignItemsTest.html b/gentest/fixtures/YGAlignItemsTest.html index c3e6af41..6b50772a 100644 --- a/gentest/fixtures/YGAlignItemsTest.html +++ b/gentest/fixtures/YGAlignItemsTest.html @@ -240,3 +240,14 @@
+ +
+
+
+
+
+
+
+
+
diff --git a/java/tests/generated/com/facebook/yoga/YGAlignItemsTest.java b/java/tests/generated/com/facebook/yoga/YGAlignItemsTest.java index a5be942b..8a32201d 100644 --- a/java/tests/generated/com/facebook/yoga/YGAlignItemsTest.java +++ b/java/tests/generated/com/facebook/yoga/YGAlignItemsTest.java @@ -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<> + * @generated SignedSource<<84597dd8b2c4f3aac1f21abe68f25308>> * generated by gentest/gentest-driver.ts from gentest/fixtures/YGAlignItemsTest.html */ @@ -2293,6 +2293,86 @@ public class YGAlignItemsTest { assertEquals(50f, root_child1.getLayoutHeight(), 0.0f); } + @Test + public void test_align_items_non_stretch_s526008() { + YogaConfig config = YogaConfigFactory.create(); + + final YogaNode root = createNode(config); + root.setPositionType(YogaPositionType.ABSOLUTE); + root.setWidth(400f); + root.setHeight(400f); + + final YogaNode root_child0 = createNode(config); + root_child0.setFlexDirection(YogaFlexDirection.ROW); + root.addChildAt(root_child0, 0); + + final YogaNode root_child0_child0 = createNode(config); + root_child0_child0.setAlignItems(YogaAlign.FLEX_START); + root_child0.addChildAt(root_child0_child0, 0); + + final YogaNode root_child0_child0_child0 = createNode(config); + root_child0_child0.addChildAt(root_child0_child0_child0, 0); + + final YogaNode root_child0_child0_child0_child0 = createNode(config); + root_child0_child0_child0_child0.setHeight(10f); + root_child0_child0_child0.addChildAt(root_child0_child0_child0_child0, 0); + root.setDirection(YogaDirection.LTR); + root.calculateLayout(YogaConstants.UNDEFINED, YogaConstants.UNDEFINED); + + assertEquals(0f, root.getLayoutX(), 0.0f); + assertEquals(0f, root.getLayoutY(), 0.0f); + assertEquals(400f, root.getLayoutWidth(), 0.0f); + assertEquals(400f, root.getLayoutHeight(), 0.0f); + + assertEquals(0f, root_child0.getLayoutX(), 0.0f); + assertEquals(0f, root_child0.getLayoutY(), 0.0f); + assertEquals(400f, root_child0.getLayoutWidth(), 0.0f); + assertEquals(10f, root_child0.getLayoutHeight(), 0.0f); + + assertEquals(0f, root_child0_child0.getLayoutX(), 0.0f); + assertEquals(0f, root_child0_child0.getLayoutY(), 0.0f); + assertEquals(0f, root_child0_child0.getLayoutWidth(), 0.0f); + assertEquals(10f, root_child0_child0.getLayoutHeight(), 0.0f); + + assertEquals(0f, root_child0_child0_child0.getLayoutX(), 0.0f); + assertEquals(0f, root_child0_child0_child0.getLayoutY(), 0.0f); + assertEquals(0f, root_child0_child0_child0.getLayoutWidth(), 0.0f); + assertEquals(10f, root_child0_child0_child0.getLayoutHeight(), 0.0f); + + assertEquals(0f, root_child0_child0_child0_child0.getLayoutX(), 0.0f); + assertEquals(0f, root_child0_child0_child0_child0.getLayoutY(), 0.0f); + assertEquals(0f, root_child0_child0_child0_child0.getLayoutWidth(), 0.0f); + assertEquals(10f, root_child0_child0_child0_child0.getLayoutHeight(), 0.0f); + + root.setDirection(YogaDirection.RTL); + root.calculateLayout(YogaConstants.UNDEFINED, YogaConstants.UNDEFINED); + + assertEquals(0f, root.getLayoutX(), 0.0f); + assertEquals(0f, root.getLayoutY(), 0.0f); + assertEquals(400f, root.getLayoutWidth(), 0.0f); + assertEquals(400f, root.getLayoutHeight(), 0.0f); + + assertEquals(0f, root_child0.getLayoutX(), 0.0f); + assertEquals(0f, root_child0.getLayoutY(), 0.0f); + assertEquals(400f, root_child0.getLayoutWidth(), 0.0f); + assertEquals(10f, root_child0.getLayoutHeight(), 0.0f); + + assertEquals(400f, root_child0_child0.getLayoutX(), 0.0f); + assertEquals(0f, root_child0_child0.getLayoutY(), 0.0f); + assertEquals(0f, root_child0_child0.getLayoutWidth(), 0.0f); + assertEquals(10f, root_child0_child0.getLayoutHeight(), 0.0f); + + assertEquals(0f, root_child0_child0_child0.getLayoutX(), 0.0f); + assertEquals(0f, root_child0_child0_child0.getLayoutY(), 0.0f); + assertEquals(0f, root_child0_child0_child0.getLayoutWidth(), 0.0f); + assertEquals(10f, root_child0_child0_child0.getLayoutHeight(), 0.0f); + + assertEquals(0f, root_child0_child0_child0_child0.getLayoutX(), 0.0f); + assertEquals(0f, root_child0_child0_child0_child0.getLayoutY(), 0.0f); + assertEquals(0f, root_child0_child0_child0_child0.getLayoutWidth(), 0.0f); + assertEquals(10f, root_child0_child0_child0_child0.getLayoutHeight(), 0.0f); + } + private YogaNode createNode(YogaConfig config) { return mNodeFactory.create(config); } diff --git a/javascript/tests/generated/YGAlignItemsTest.test.ts b/javascript/tests/generated/YGAlignItemsTest.test.ts index 39c013a3..ae4dc635 100644 --- a/javascript/tests/generated/YGAlignItemsTest.test.ts +++ b/javascript/tests/generated/YGAlignItemsTest.test.ts @@ -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<> * 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(); + } +}); diff --git a/tests/generated/YGAlignItemsTest.cpp b/tests/generated/YGAlignItemsTest.cpp index 4a4f48ec..e64d68e4 100644 --- a/tests/generated/YGAlignItemsTest.cpp +++ b/tests/generated/YGAlignItemsTest.cpp @@ -5,7 +5,7 @@ * LICENSE file in the root directory of this source tree. * * clang-format off - * @generated SignedSource<<71295a398c89ea424490884a05e2c77c>> + * @generated SignedSource<<1db57b05babb408c08efcec7dbdf16fb>> * generated by gentest/gentest-driver.ts from gentest/fixtures/YGAlignItemsTest.html */ @@ -2310,3 +2310,84 @@ TEST(YogaTest, align_stretch_with_row_reverse) { YGConfigFree(config); } + +TEST(YogaTest, align_items_non_stretch_s526008) { + YGConfigRef config = YGConfigNew(); + + YGNodeRef root = YGNodeNewWithConfig(config); + YGNodeStyleSetPositionType(root, YGPositionTypeAbsolute); + YGNodeStyleSetWidth(root, 400); + YGNodeStyleSetHeight(root, 400); + + YGNodeRef root_child0 = YGNodeNewWithConfig(config); + YGNodeStyleSetFlexDirection(root_child0, YGFlexDirectionRow); + YGNodeInsertChild(root, root_child0, 0); + + YGNodeRef root_child0_child0 = YGNodeNewWithConfig(config); + YGNodeStyleSetAlignItems(root_child0_child0, YGAlignFlexStart); + YGNodeInsertChild(root_child0, root_child0_child0, 0); + + YGNodeRef root_child0_child0_child0 = YGNodeNewWithConfig(config); + YGNodeInsertChild(root_child0_child0, root_child0_child0_child0, 0); + + YGNodeRef root_child0_child0_child0_child0 = YGNodeNewWithConfig(config); + YGNodeStyleSetHeight(root_child0_child0_child0_child0, 10); + YGNodeInsertChild(root_child0_child0_child0, root_child0_child0_child0_child0, 0); + YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR); + + ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root)); + ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root)); + ASSERT_FLOAT_EQ(400, YGNodeLayoutGetWidth(root)); + ASSERT_FLOAT_EQ(400, YGNodeLayoutGetHeight(root)); + + ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0)); + ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0)); + ASSERT_FLOAT_EQ(400, YGNodeLayoutGetWidth(root_child0)); + ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child0)); + + ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0_child0)); + ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0_child0)); + ASSERT_FLOAT_EQ(0, YGNodeLayoutGetWidth(root_child0_child0)); + ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child0_child0)); + + ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0_child0_child0)); + ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0_child0_child0)); + ASSERT_FLOAT_EQ(0, YGNodeLayoutGetWidth(root_child0_child0_child0)); + ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child0_child0_child0)); + + ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0_child0_child0_child0)); + ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0_child0_child0_child0)); + ASSERT_FLOAT_EQ(0, YGNodeLayoutGetWidth(root_child0_child0_child0_child0)); + ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child0_child0_child0_child0)); + + YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL); + + ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root)); + ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root)); + ASSERT_FLOAT_EQ(400, YGNodeLayoutGetWidth(root)); + ASSERT_FLOAT_EQ(400, YGNodeLayoutGetHeight(root)); + + ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0)); + ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0)); + ASSERT_FLOAT_EQ(400, YGNodeLayoutGetWidth(root_child0)); + ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child0)); + + ASSERT_FLOAT_EQ(400, YGNodeLayoutGetLeft(root_child0_child0)); + ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0_child0)); + ASSERT_FLOAT_EQ(0, YGNodeLayoutGetWidth(root_child0_child0)); + ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child0_child0)); + + ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0_child0_child0)); + ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0_child0_child0)); + ASSERT_FLOAT_EQ(0, YGNodeLayoutGetWidth(root_child0_child0_child0)); + ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child0_child0_child0)); + + ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0_child0_child0_child0)); + ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0_child0_child0_child0)); + ASSERT_FLOAT_EQ(0, YGNodeLayoutGetWidth(root_child0_child0_child0_child0)); + ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child0_child0_child0_child0)); + + YGNodeFreeRecursive(root); + + YGConfigFree(config); +} diff --git a/yoga/algorithm/CalculateLayout.cpp b/yoga/algorithm/CalculateLayout.cpp index 36184745..8c4eaef9 100644 --- a/yoga/algorithm/CalculateLayout.cpp +++ b/yoga/algorithm/CalculateLayout.cpp @@ -415,6 +415,12 @@ static void measureNodeWithoutChildren( Dimension::Height); } +inline bool isFixedSize(float dim, SizingMode sizingMode) { + return sizingMode == SizingMode::StretchFit || + (yoga::isDefined(dim) && sizingMode == SizingMode::FitContent && + dim <= 0.0); +} + static bool measureNodeWithFixedSize( yoga::Node* const node, const Direction direction, @@ -424,12 +430,8 @@ static bool measureNodeWithFixedSize( const SizingMode heightSizingMode, const float ownerWidth, const float ownerHeight) { - if ((yoga::isDefined(availableWidth) && - widthSizingMode == SizingMode::FitContent && availableWidth <= 0.0f) || - (yoga::isDefined(availableHeight) && - heightSizingMode == SizingMode::FitContent && availableHeight <= 0.0f) || - (widthSizingMode == SizingMode::StretchFit && - heightSizingMode == SizingMode::StretchFit)) { + if (isFixedSize(availableWidth, widthSizingMode) && + isFixedSize(availableHeight, heightSizingMode)) { node->setLayoutMeasuredDimension( boundAxis( node, -- 2.50.1.windows.1 From 73980a3cf870c61613231dc13c0f7f59f590f9d4 Mon Sep 17 00:00:00 2001 From: Nolan O'Brien Date: Wed, 2 Jul 2025 14:21:18 -0700 Subject: [PATCH 12/32] Fix exhaustive switches Summary: X-link: https://github.com/facebook/react-native/pull/52379 Changelog: [General][Fixed] - Add `default:` case to avoid warnings/errors for targets that compile with `-Wswitch-enum` and `-Wswitch-default` enabled Reviewed By: aary, yungsters, astreet Differential Revision: D77051152 fbshipit-source-id: 100b10f97cb3a5d73f1e3dcaf1b284baf6a43982 --- yoga/YGValue.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/yoga/YGValue.h b/yoga/YGValue.h index 63c82f3d..b7c4ba25 100644 --- a/yoga/YGValue.h +++ b/yoga/YGValue.h @@ -72,9 +72,9 @@ inline bool operator==(const YGValue& lhs, const YGValue& rhs) { case YGUnitPoint: case YGUnitPercent: return lhs.value == rhs.value; + default: + return false; } - - return false; } inline bool operator!=(const YGValue& lhs, const YGValue& rhs) { -- 2.50.1.windows.1 From c7c85621fc5a70ef2a169a1fe359acf38476e4cd Mon Sep 17 00:00:00 2001 From: Jakub Piasecki Date: Fri, 11 Jul 2025 02:16:35 -0700 Subject: [PATCH 13/32] Fix `display: contents` nodes not being cloned with the wrong owner (#1826) Summary: X-link: https://github.com/facebook/react-native/pull/52530 This PR fixes two issues with `display: contents` implementation: 1. When a node with `display: contents` set is a leaf, it won't be cloned after the initial tree is built. The added test case covers this scenario. 2. It was possible for the subtree of `display: contents` nodes not to be cloned during layout. I don't have a minimal reproduction for this one, unfortunately. It was discovered in the Expensify app: https://github.com/Expensify/App/issues/65268, along with a consistent reproduction. In that specific case, it seems to be heavily tied to `react-native-onyx`, which is a state management library. Changelog: [GENERAL][FIXED] - Fixed nodes with `display: contents` set being cloned with the wrong owner Pull Request resolved: https://github.com/facebook/yoga/pull/1826 Reviewed By: adityasharat, NickGerleman Differential Revision: D78084270 Pulled By: j-piasecki fbshipit-source-id: eb81f6d7dcd1665974d07261ba693e2abea239bb --- tests/YGPersistentNodeCloningTest.cpp | 30 +++++++++++++++++++++++++++ yoga/algorithm/CalculateLayout.cpp | 21 +++++++++++-------- yoga/node/Node.cpp | 28 +++++++++++++++++++++++++ yoga/node/Node.h | 10 +++++---- 4 files changed, 76 insertions(+), 13 deletions(-) diff --git a/tests/YGPersistentNodeCloningTest.cpp b/tests/YGPersistentNodeCloningTest.cpp index 137da26c..41239323 100644 --- a/tests/YGPersistentNodeCloningTest.cpp +++ b/tests/YGPersistentNodeCloningTest.cpp @@ -181,4 +181,34 @@ TEST_F( EXPECT_EQ(nodesCloned[0], a.get()); } +TEST_F(YGPersistentNodeCloningTest, clone_leaf_display_contents_node) { + // + // + // + + auto b = std::make_shared(config); + auto a = std::make_shared(config, std::vector{b}); + YGNodeStyleSetDisplay(b->node, YGDisplayContents); + + // We don't expect any cloning during the first layout + onClone = [](...) { FAIL(); }; + + YGNodeCalculateLayout(a->node, YGUndefined, YGUndefined, YGDirectionLTR); + + auto aPrime = std::make_shared(config, std::vector{b}); + + std::vector nodesCloned; + // We should clone "C" + onClone = [&](YGNodeConstRef oldNode, + YGNodeConstRef /*owner*/, + size_t /*childIndex*/) { + nodesCloned.push_back(static_cast(YGNodeGetContext(oldNode))); + }; + + YGNodeCalculateLayout(aPrime->node, 100, 100, YGDirectionLTR); + + EXPECT_EQ(nodesCloned.size(), 1); + EXPECT_EQ(nodesCloned[0], b.get()); +} + } // namespace facebook::yoga diff --git a/yoga/algorithm/CalculateLayout.cpp b/yoga/algorithm/CalculateLayout.cpp index 8c4eaef9..db790428 100644 --- a/yoga/algorithm/CalculateLayout.cpp +++ b/yoga/algorithm/CalculateLayout.cpp @@ -478,16 +478,19 @@ static void zeroOutLayoutRecursively(yoga::Node* const node) { } static void cleanupContentsNodesRecursively(yoga::Node* const node) { - for (auto child : node->getChildren()) { - if (child->style().display() == Display::Contents) { - child->getLayout() = {}; - child->setLayoutDimension(0, Dimension::Width); - child->setLayoutDimension(0, Dimension::Height); - child->setHasNewLayout(true); - child->setDirty(false); - child->cloneChildrenIfNeeded(); + if (node->hasContentsChildren()) [[unlikely]] { + node->cloneContentsChildrenIfNeeded(); + for (auto child : node->getChildren()) { + if (child->style().display() == Display::Contents) { + child->getLayout() = {}; + child->setLayoutDimension(0, Dimension::Width); + child->setLayoutDimension(0, Dimension::Height); + child->setHasNewLayout(true); + child->setDirty(false); + child->cloneChildrenIfNeeded(); - cleanupContentsNodesRecursively(child); + cleanupContentsNodesRecursively(child); + } } } } diff --git a/yoga/node/Node.cpp b/yoga/node/Node.cpp index fbdf5c1b..d42bd5f9 100644 --- a/yoga/node/Node.cpp +++ b/yoga/node/Node.cpp @@ -181,6 +181,17 @@ void Node::setDirty(bool isDirty) { } } +void Node::setChildren(const std::vector& children) { + children_ = children; + + contentsChildrenCount_ = 0; + for (const auto& child : children) { + if (child->style().display() == Display::Contents) { + contentsChildrenCount_++; + } + } +} + bool Node::removeChild(Node* child) { auto p = std::find(children_.begin(), children_.end(), child); if (p != children_.end()) { @@ -380,6 +391,23 @@ void Node::cloneChildrenIfNeeded() { if (child->getOwner() != this) { child = resolveRef(config_->cloneNode(child, this, i)); child->setOwner(this); + + if (child->hasContentsChildren()) [[unlikely]] { + child->cloneContentsChildrenIfNeeded(); + } + } + i += 1; + } +} + +void Node::cloneContentsChildrenIfNeeded() { + size_t i = 0; + for (Node*& child : children_) { + if (child->style().display() == Display::Contents && + child->getOwner() != this) { + child = resolveRef(config_->cloneNode(child, this, i)); + child->setOwner(this); + child->cloneChildrenIfNeeded(); } i += 1; } diff --git a/yoga/node/Node.h b/yoga/node/Node.h index 5ae7d432..8068c814 100644 --- a/yoga/node/Node.h +++ b/yoga/node/Node.h @@ -96,6 +96,10 @@ class YG_EXPORT Node : public ::YGNode { return config_->hasErrata(errata); } + bool hasContentsChildren() const { + return contentsChildrenCount_ != 0; + } + YGDirtiedFunc getDirtiedFunc() const { return dirtiedFunc_; } @@ -244,15 +248,12 @@ class YG_EXPORT Node : public ::YGNode { owner_ = owner; } - void setChildren(const std::vector& children) { - children_ = children; - } - // TODO: rvalue override for setChildren void setConfig(Config* config); void setDirty(bool isDirty); + void setChildren(const std::vector& children); void setLayoutLastOwnerDirection(Direction direction); void setLayoutComputedFlexBasis(FloatOptional computedFlexBasis); void setLayoutComputedFlexBasisGeneration( @@ -286,6 +287,7 @@ class YG_EXPORT Node : public ::YGNode { void removeChild(size_t index); void cloneChildrenIfNeeded(); + void cloneContentsChildrenIfNeeded(); void markDirtyAndPropagate(); float resolveFlexGrow() const; float resolveFlexShrink() const; -- 2.50.1.windows.1 From 9f2a9476e5a8fdd7dec0891d69077eff6265c998 Mon Sep 17 00:00:00 2001 From: Alexey Medvedev Date: Thu, 24 Jul 2025 16:51:13 -0700 Subject: [PATCH 14/32] Make yoga/Yoga.h an umbrell header (#1828) Summary: X-link: https://github.com/facebook/react-native/pull/52817 Pull Request resolved: https://github.com/facebook/yoga/pull/1828 X-link: https://github.com/facebook/litho/pull/1070 This diff makes the Yoga/Yoga.h header an umbrella header, which means that it includes all of Yoga's public headers. The code changes in each file include adding the IWYU pragma export to each header file, which is a way to tell the compiler to export the header file's symbols to other files that include it. This is necessary for the header file to be used as an umbrella header. Changelog: [General][Added] - Code quality fixes Reviewed By: corporateshark Differential Revision: D78692457 fbshipit-source-id: 7fcd53d2a6f268fa4377dbd5bd6ba6eebc94b5f8 --- yoga/Yoga.h | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/yoga/Yoga.h b/yoga/Yoga.h index 2a4f2059..97f05ed3 100644 --- a/yoga/Yoga.h +++ b/yoga/Yoga.h @@ -11,11 +11,11 @@ * `#include ` includes all of Yoga's public headers. */ -#include -#include -#include -#include -#include -#include -#include -#include +#include // IWYU pragma: export +#include // IWYU pragma: export +#include // IWYU pragma: export +#include // IWYU pragma: export +#include // IWYU pragma: export +#include // IWYU pragma: export +#include // IWYU pragma: export +#include // IWYU pragma: export -- 2.50.1.windows.1 From 82671c01324de66bad60272bf121759a8f8346fa Mon Sep 17 00:00:00 2001 From: Dmitry Polukhin Date: Wed, 30 Jul 2025 03:39:00 -0700 Subject: [PATCH 15/32] Disable modernize-avoid-c-arrays in xplat/yoga/tests Reviewed By: JuanBesa, rshest Differential Revision: D79247609 fbshipit-source-id: 529ba950ab200c46493152b81dece6bd76f6fdbd --- tests/.clang-tidy | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 tests/.clang-tidy diff --git a/tests/.clang-tidy b/tests/.clang-tidy new file mode 100644 index 00000000..fcb485a9 --- /dev/null +++ b/tests/.clang-tidy @@ -0,0 +1,7 @@ +--- +InheritParentConfig: true +Checks: ' +-facebook-hte-CArray, +-modernize-avoid-c-arrays, +' +... -- 2.50.1.windows.1 From 8bf7a34d021d20f923e635276ebbd72d850245d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateo=20Guzm=C3=A1n?= Date: Thu, 7 Aug 2025 08:17:56 -0700 Subject: [PATCH 16/32] Initial Kotlin setup and migrate `YogaConstants` (#1829) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Summary: X-link: https://github.com/facebook/react-native/pull/53133 # Changelog: [Internal] - As part of the ongoing effort to migrate the React Native codebase to Kotlin, this PR introduces the initial setup required for Kotlin support in Yoga. - Added initial basic Kotlin configuration to the project. - Migrated `YogaConstants` as an initial file to try out the first migration steps. Pull Request resolved: https://github.com/facebook/yoga/pull/1829 Test Plan: - Tested the migrated class directly against facebook/react-native, see the PR [here](https://github.com/facebook/react-native/pull/52998). - Run: `./gradlew :yoga:assembleDebug` & `./gradlew :yoga:compileDebugSources` I am not able to run the Java tests in this repo (even before the initial Kotlin setup) – not sure if I am missing something there but any pointers are welcome – it seems like there is some missing configuration. Currently trying with `./gradlew :yoga:test` Reviewed By: cortinico Differential Revision: D79545992 Pulled By: rshest fbshipit-source-id: 8257ff53e6b6f2436980be98b6c94e1ac526b207 --- .gitignore | 3 +++ build.gradle | 1 + java/build.gradle.kts | 4 ++++ java/com/facebook/yoga/YogaConstants.java | 25 ----------------------- java/com/facebook/yoga/YogaConstants.kt | 18 ++++++++++++++++ 5 files changed, 26 insertions(+), 25 deletions(-) delete mode 100644 java/com/facebook/yoga/YogaConstants.java create mode 100644 java/com/facebook/yoga/YogaConstants.kt diff --git a/.gitignore b/.gitignore index 7d75c154..8b846f08 100644 --- a/.gitignore +++ b/.gitignore @@ -73,3 +73,6 @@ local.properties # Docusarus build .docusaurus + +# Android Studio +.idea diff --git a/build.gradle b/build.gradle index 6352e5c9..153c3db5 100644 --- a/build.gradle +++ b/build.gradle @@ -9,6 +9,7 @@ plugins { id("com.android.library") version "8.7.1" apply false id("com.android.application") version "8.7.1" apply false id("io.github.gradle-nexus.publish-plugin") version "1.3.0" + id 'org.jetbrains.kotlin.android' version '2.1.20' apply false } allprojects { diff --git a/java/build.gradle.kts b/java/build.gradle.kts index 2d2f874d..4c73e6ab 100644 --- a/java/build.gradle.kts +++ b/java/build.gradle.kts @@ -9,6 +9,7 @@ plugins { id("com.android.library") id("maven-publish") id("signing") + id("org.jetbrains.kotlin.android") } group = "com.facebook.yoga" @@ -48,6 +49,8 @@ android { } } + kotlinOptions { jvmTarget = "1.8" } + publishing { multipleVariants { withSourcesJar() @@ -60,6 +63,7 @@ android { dependencies { implementation("com.google.code.findbugs:jsr305:3.0.2") implementation("com.facebook.soloader:soloader:0.10.5") + implementation("androidx.core:core-ktx:1.16.0") testImplementation("junit:junit:4.12") } diff --git a/java/com/facebook/yoga/YogaConstants.java b/java/com/facebook/yoga/YogaConstants.java deleted file mode 100644 index f8205fc6..00000000 --- a/java/com/facebook/yoga/YogaConstants.java +++ /dev/null @@ -1,25 +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. - */ - -package com.facebook.yoga; - -public class YogaConstants { - - public static final float UNDEFINED = Float.NaN; - - public static boolean isUndefined(float value) { - return Float.compare(value, UNDEFINED) == 0; - } - - public static boolean isUndefined(YogaValue value) { - return value.unit == YogaUnit.UNDEFINED; - } - - public static float getUndefined() { - return UNDEFINED; - } -} diff --git a/java/com/facebook/yoga/YogaConstants.kt b/java/com/facebook/yoga/YogaConstants.kt new file mode 100644 index 00000000..eb768841 --- /dev/null +++ b/java/com/facebook/yoga/YogaConstants.kt @@ -0,0 +1,18 @@ +/* + * 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.yoga + +public object YogaConstants { + @JvmField public val UNDEFINED: Float = Float.NaN + + @JvmStatic public fun isUndefined(value: Float): Boolean = value.compareTo(UNDEFINED) == 0 + + @JvmStatic public fun isUndefined(value: YogaValue): Boolean = value.unit == YogaUnit.UNDEFINED + + @JvmStatic public fun getUndefined(): Float = UNDEFINED +} -- 2.50.1.windows.1 From da5ba7f7c6d15fbcc8a1f054de96408588bcc30f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateo=20Guzm=C3=A1n?= Date: Mon, 11 Aug 2025 08:47:34 -0700 Subject: [PATCH 17/32] Migrate `YogaLogger` to Kotlin (#1834) Summary: Migrate com.facebook.yoga.YogaLogger to Kotlin. Pull Request resolved: https://github.com/facebook/yoga/pull/1834 Test Plan: RN ```sh yarn android yarn test-android ``` Yoga ```sh ./gradlew :yoga:assembleDebug ``` Reviewed By: rshest Differential Revision: D79897742 Pulled By: cortinico fbshipit-source-id: 79b926a7abadce9038fc55ad0f608e92bc77a55a --- .../yoga/{YogaLogger.java => YogaLogger.kt} | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) rename java/com/facebook/yoga/{YogaLogger.java => YogaLogger.kt} (52%) diff --git a/java/com/facebook/yoga/YogaLogger.java b/java/com/facebook/yoga/YogaLogger.kt similarity index 52% rename from java/com/facebook/yoga/YogaLogger.java rename to java/com/facebook/yoga/YogaLogger.kt index f40292dd..bc0a6fb3 100644 --- a/java/com/facebook/yoga/YogaLogger.java +++ b/java/com/facebook/yoga/YogaLogger.kt @@ -5,16 +5,15 @@ * LICENSE file in the root directory of this source tree. */ -package com.facebook.yoga; +package com.facebook.yoga -import com.facebook.yoga.annotations.DoNotStrip; +import com.facebook.yoga.annotations.DoNotStrip /** - * Interface for receiving logs from native layer. Use by setting YogaNode.setLogger(myLogger); - * See YogaLogLevel for the different log levels. + * Interface for receiving logs from native layer. Use by setting YogaNode.setLogger(myLogger); See + * YogaLogLevel for the different log levels. */ @DoNotStrip -public interface YogaLogger { - @DoNotStrip - void log(YogaLogLevel level, String message); +public fun interface YogaLogger { + @DoNotStrip public fun log(level: YogaLogLevel, message: String) } -- 2.50.1.windows.1 From d4b5220e6c56579a204b4a8e53194681088db0ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateo=20Guzm=C3=A1n?= Date: Mon, 11 Aug 2025 10:51:55 -0700 Subject: [PATCH 18/32] Migrate `YogaBaselineFunction` to Kotlin (#1831) Summary: Migrate com.facebook.yoga.YogaBaselineFunction to Kotlin. Pull Request resolved: https://github.com/facebook/yoga/pull/1831 Test Plan: RN ```sh yarn android yarn test-android ``` Yoga ```sh ./gradlew :yoga:assembleDebug ``` Reviewed By: joevilches, mdvacca Differential Revision: D79897676 Pulled By: cortinico fbshipit-source-id: 2f175bf60a871c4635d1575faec1096f9c970f48 --- .../{YogaBaselineFunction.java => YogaBaselineFunction.kt} | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) rename java/com/facebook/yoga/{YogaBaselineFunction.java => YogaBaselineFunction.kt} (70%) diff --git a/java/com/facebook/yoga/YogaBaselineFunction.java b/java/com/facebook/yoga/YogaBaselineFunction.kt similarity index 70% rename from java/com/facebook/yoga/YogaBaselineFunction.java rename to java/com/facebook/yoga/YogaBaselineFunction.kt index d3444215..b061fc88 100644 --- a/java/com/facebook/yoga/YogaBaselineFunction.java +++ b/java/com/facebook/yoga/YogaBaselineFunction.kt @@ -5,12 +5,12 @@ * LICENSE file in the root directory of this source tree. */ -package com.facebook.yoga; +package com.facebook.yoga -public interface YogaBaselineFunction { +public fun interface YogaBaselineFunction { /** * Return the baseline of the node in points. When no baseline function is set the baseline * default to the computed height of the node. */ - float baseline(YogaNode node, float width, float height); + public fun baseline(node: YogaNode, width: Float, height: Float): Float } -- 2.50.1.windows.1 From 714d4b2ebe64381820b36dbeb4e23a29102d06aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateo=20Guzm=C3=A1n?= Date: Tue, 12 Aug 2025 03:34:21 -0700 Subject: [PATCH 19/32] Migrate `YogaStyleInputs` to Kotlin (#1830) Summary: Migrate com.facebook.yoga.YogaStyleInputs to Kotlin. Pull Request resolved: https://github.com/facebook/yoga/pull/1830 Test Plan: RN ```sh yarn android yarn test-android ``` Yoga ```sh ./gradlew :yoga:assembleDebug ``` Reviewed By: rshest Differential Revision: D79897662 Pulled By: cortinico fbshipit-source-id: a4063a8c0f608050162cd3707834040e35f9ebf7 --- java/com/facebook/yoga/YogaStyleInputs.java | 51 --------------------- java/com/facebook/yoga/YogaStyleInputs.kt | 51 +++++++++++++++++++++ 2 files changed, 51 insertions(+), 51 deletions(-) delete mode 100644 java/com/facebook/yoga/YogaStyleInputs.java create mode 100644 java/com/facebook/yoga/YogaStyleInputs.kt diff --git a/java/com/facebook/yoga/YogaStyleInputs.java b/java/com/facebook/yoga/YogaStyleInputs.java deleted file mode 100644 index 405a2770..00000000 --- a/java/com/facebook/yoga/YogaStyleInputs.java +++ /dev/null @@ -1,51 +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. - */ - -package com.facebook.yoga; - -public class YogaStyleInputs { - public static final short LAYOUT_DIRECTION = 0; - public static final short FLEX_DIRECTION = 1; - public static final short FLEX = 2; - public static final short FLEX_GROW = 3; - public static final short FLEX_SHRINK = 4; - public static final short FLEX_BASIS = 5; - public static final short FLEX_BASIS_PERCENT = 6; - public static final short FLEX_BASIS_AUTO = 7; - public static final short FLEX_WRAP = 8; - public static final short WIDTH = 9; - public static final short WIDTH_PERCENT = 10; - public static final short WIDTH_AUTO = 11; - public static final short MIN_WIDTH = 12; - public static final short MIN_WIDTH_PERCENT = 13; - public static final short MAX_WIDTH = 14; - public static final short MAX_WIDTH_PERCENT = 15; - public static final short HEIGHT = 16; - public static final short HEIGHT_PERCENT = 17; - public static final short HEIGHT_AUTO = 18; - public static final short MIN_HEIGHT = 19; - public static final short MIN_HEIGHT_PERCENT = 20; - public static final short MAX_HEIGHT = 21; - public static final short MAX_HEIGHT_PERCENT = 22; - public static final short JUSTIFY_CONTENT = 23; - public static final short ALIGN_ITEMS = 24; - public static final short ALIGN_SELF = 25; - public static final short ALIGN_CONTENT = 26; - public static final short POSITION_TYPE = 27; - public static final short ASPECT_RATIO = 28; - public static final short OVERFLOW = 29; - public static final short DISPLAY = 30; - public static final short MARGIN = 31; - public static final short MARGIN_PERCENT = 32; - public static final short MARGIN_AUTO = 33; - public static final short PADDING = 34; - public static final short PADDING_PERCENT = 35; - public static final short BORDER = 36; - public static final short POSITION = 37; - public static final short POSITION_PERCENT = 38; - public static final short IS_REFERENCE_BASELINE = 39; -} diff --git a/java/com/facebook/yoga/YogaStyleInputs.kt b/java/com/facebook/yoga/YogaStyleInputs.kt new file mode 100644 index 00000000..33c439a6 --- /dev/null +++ b/java/com/facebook/yoga/YogaStyleInputs.kt @@ -0,0 +1,51 @@ +/* + * 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.yoga + +public object YogaStyleInputs { + public const val LAYOUT_DIRECTION: Short = 0 + public const val FLEX_DIRECTION: Short = 1 + public const val FLEX: Short = 2 + public const val FLEX_GROW: Short = 3 + public const val FLEX_SHRINK: Short = 4 + public const val FLEX_BASIS: Short = 5 + public const val FLEX_BASIS_PERCENT: Short = 6 + public const val FLEX_BASIS_AUTO: Short = 7 + public const val FLEX_WRAP: Short = 8 + public const val WIDTH: Short = 9 + public const val WIDTH_PERCENT: Short = 10 + public const val WIDTH_AUTO: Short = 11 + public const val MIN_WIDTH: Short = 12 + public const val MIN_WIDTH_PERCENT: Short = 13 + public const val MAX_WIDTH: Short = 14 + public const val MAX_WIDTH_PERCENT: Short = 15 + public const val HEIGHT: Short = 16 + public const val HEIGHT_PERCENT: Short = 17 + public const val HEIGHT_AUTO: Short = 18 + public const val MIN_HEIGHT: Short = 19 + public const val MIN_HEIGHT_PERCENT: Short = 20 + public const val MAX_HEIGHT: Short = 21 + public const val MAX_HEIGHT_PERCENT: Short = 22 + public const val JUSTIFY_CONTENT: Short = 23 + public const val ALIGN_ITEMS: Short = 24 + public const val ALIGN_SELF: Short = 25 + public const val ALIGN_CONTENT: Short = 26 + public const val POSITION_TYPE: Short = 27 + public const val ASPECT_RATIO: Short = 28 + public const val OVERFLOW: Short = 29 + public const val DISPLAY: Short = 30 + public const val MARGIN: Short = 31 + public const val MARGIN_PERCENT: Short = 32 + public const val MARGIN_AUTO: Short = 33 + public const val PADDING: Short = 34 + public const val PADDING_PERCENT: Short = 35 + public const val BORDER: Short = 36 + public const val POSITION: Short = 37 + public const val POSITION_PERCENT: Short = 38 + public const val IS_REFERENCE_BASELINE: Short = 39 +} -- 2.50.1.windows.1 From d1037226c0576350302a5e9aff4c939ee27d2ae6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateo=20Guzm=C3=A1n?= Date: Tue, 12 Aug 2025 07:40:31 -0700 Subject: [PATCH 20/32] Migrate `YogaMeasureFunction` to Kotlin (#1835) Summary: Migrate com.facebook.yoga.YogaMeasureFunction to Kotlin. Pull Request resolved: https://github.com/facebook/yoga/pull/1835 Test Plan: RN ```sh yarn android yarn test-android ``` Yoga ```sh ./gradlew :yoga:assembleDebug ``` Reviewed By: mdvacca Differential Revision: D79897728 Pulled By: cortinico fbshipit-source-id: 959ae976622838147685cf6088674dce25f5cc99 --- .../facebook/yoga/YogaMeasureFunction.java | 20 ------------------- java/com/facebook/yoga/YogaMeasureFunction.kt | 19 ++++++++++++++++++ 2 files changed, 19 insertions(+), 20 deletions(-) delete mode 100644 java/com/facebook/yoga/YogaMeasureFunction.java create mode 100644 java/com/facebook/yoga/YogaMeasureFunction.kt diff --git a/java/com/facebook/yoga/YogaMeasureFunction.java b/java/com/facebook/yoga/YogaMeasureFunction.java deleted file mode 100644 index 21da35fe..00000000 --- a/java/com/facebook/yoga/YogaMeasureFunction.java +++ /dev/null @@ -1,20 +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. - */ - -package com.facebook.yoga; - -public interface YogaMeasureFunction { - /** - * Return a value created by YogaMeasureOutput.make(width, height); - */ - long measure( - YogaNode node, - float width, - YogaMeasureMode widthMode, - float height, - YogaMeasureMode heightMode); -} diff --git a/java/com/facebook/yoga/YogaMeasureFunction.kt b/java/com/facebook/yoga/YogaMeasureFunction.kt new file mode 100644 index 00000000..10b5cfc0 --- /dev/null +++ b/java/com/facebook/yoga/YogaMeasureFunction.kt @@ -0,0 +1,19 @@ +/* + * 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.yoga + +public fun interface YogaMeasureFunction { + /** Return a value created by YogaMeasureOutput.make(width, height); */ + public fun measure( + node: YogaNode, + width: Float, + widthMode: YogaMeasureMode, + height: Float, + heightMode: YogaMeasureMode + ): Long +} -- 2.50.1.windows.1 From cf50bc9adfee1eb03a65589c10fe1c2fe54e6381 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateo=20Guzm=C3=A1n?= Date: Tue, 12 Aug 2025 07:55:41 -0700 Subject: [PATCH 21/32] Migrate `YogaMeasureOutput` to Kotlin (#1842) Summary: Migrate com.facebook.yoga.YogaMeasureOutput to Kotlin. Pull Request resolved: https://github.com/facebook/yoga/pull/1842 Test Plan: RN ```sh yarn android yarn test-android ``` Yoga ```sh ./gradlew :yoga:assembleDebug ``` Reviewed By: rshest Differential Revision: D79897681 Pulled By: cortinico fbshipit-source-id: 63280b6aed9bbeeb1e71458a1793c9647dcf0726 --- java/com/facebook/yoga/YogaMeasureOutput.java | 32 ------------------- java/com/facebook/yoga/YogaMeasureOutput.kt | 29 +++++++++++++++++ 2 files changed, 29 insertions(+), 32 deletions(-) delete mode 100644 java/com/facebook/yoga/YogaMeasureOutput.java create mode 100644 java/com/facebook/yoga/YogaMeasureOutput.kt diff --git a/java/com/facebook/yoga/YogaMeasureOutput.java b/java/com/facebook/yoga/YogaMeasureOutput.java deleted file mode 100644 index c7a77aba..00000000 --- a/java/com/facebook/yoga/YogaMeasureOutput.java +++ /dev/null @@ -1,32 +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. - */ - -package com.facebook.yoga; - -/** - * Helpers for building measure output value. - */ -public class YogaMeasureOutput { - - public static long make(float width, float height) { - final int wBits = Float.floatToRawIntBits(width); - final int hBits = Float.floatToRawIntBits(height); - return ((long) wBits) << 32 | ((long) hBits); - } - - public static long make(int width, int height) { - return make((float) width, (float) height); - } - - public static float getWidth(long measureOutput) { - return Float.intBitsToFloat((int) (0xFFFFFFFF & (measureOutput >> 32))); - } - - public static float getHeight(long measureOutput) { - return Float.intBitsToFloat((int) (0xFFFFFFFF & measureOutput)); - } -} diff --git a/java/com/facebook/yoga/YogaMeasureOutput.kt b/java/com/facebook/yoga/YogaMeasureOutput.kt new file mode 100644 index 00000000..9185ef46 --- /dev/null +++ b/java/com/facebook/yoga/YogaMeasureOutput.kt @@ -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. + */ + +package com.facebook.yoga + +/** Helpers for building measure output value. */ +public object YogaMeasureOutput { + @JvmStatic + public fun make(width: Float, height: Float): Long { + val wBits = java.lang.Float.floatToRawIntBits(width) + val hBits = java.lang.Float.floatToRawIntBits(height) + return (wBits.toLong()) shl 32 or (hBits.toLong()) + } + + @JvmStatic + public fun make(width: Int, height: Int): Long = make(width.toFloat(), height.toFloat()) + + @JvmStatic + public fun getWidth(measureOutput: Long): Float = + java.lang.Float.intBitsToFloat((0xFFFFFFFFL and (measureOutput shr 32)).toInt()) + + @JvmStatic + public fun getHeight(measureOutput: Long): Float = + java.lang.Float.intBitsToFloat((0xFFFFFFFFL and measureOutput).toInt()) +} -- 2.50.1.windows.1 From c54215fd775a9b190592e3fc00dedac7744c93b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateo=20Guzm=C3=A1n?= Date: Tue, 12 Aug 2025 08:57:43 -0700 Subject: [PATCH 22/32] Migrate `YogaNodeFactory` to Kotlin (#1832) Summary: Migrate com.facebook.yoga.YogaNodeFactory to Kotlin. Pull Request resolved: https://github.com/facebook/yoga/pull/1832 Test Plan: RN ```sh yarn android yarn test-android ``` Yoga ```sh ./gradlew :yoga:assembleDebug ``` Reviewed By: zielinskimz Differential Revision: D79897733 Pulled By: cortinico fbshipit-source-id: 3ea4f5635eb8c910719c13d3087356b96b6f0746 --- java/com/facebook/yoga/YogaNodeFactory.java | 18 ------------------ java/com/facebook/yoga/YogaNodeFactory.kt | 14 ++++++++++++++ 2 files changed, 14 insertions(+), 18 deletions(-) delete mode 100644 java/com/facebook/yoga/YogaNodeFactory.java create mode 100644 java/com/facebook/yoga/YogaNodeFactory.kt diff --git a/java/com/facebook/yoga/YogaNodeFactory.java b/java/com/facebook/yoga/YogaNodeFactory.java deleted file mode 100644 index 912083a7..00000000 --- a/java/com/facebook/yoga/YogaNodeFactory.java +++ /dev/null @@ -1,18 +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. - */ - -package com.facebook.yoga; - -public abstract class YogaNodeFactory { - public static YogaNode create() { - return new YogaNodeJNIFinalizer(); - } - - public static YogaNode create(YogaConfig config) { - return new YogaNodeJNIFinalizer(config); - } -} diff --git a/java/com/facebook/yoga/YogaNodeFactory.kt b/java/com/facebook/yoga/YogaNodeFactory.kt new file mode 100644 index 00000000..ead0d2be --- /dev/null +++ b/java/com/facebook/yoga/YogaNodeFactory.kt @@ -0,0 +1,14 @@ +/* + * 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.yoga + +public object YogaNodeFactory { + @JvmStatic public fun create(): YogaNode = YogaNodeJNIFinalizer() + + @JvmStatic public fun create(config: YogaConfig): YogaNode = YogaNodeJNIFinalizer(config) +} -- 2.50.1.windows.1 From c90aecbdfe96220b3e322a9f9523ac4060a25166 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateo=20Guzm=C3=A1n?= Date: Tue, 12 Aug 2025 09:10:30 -0700 Subject: [PATCH 23/32] Migrate `LayoutPassReason` to Kotlin (#1836) Summary: Migrate com.facebook.yoga.LayoutPassReason to Kotlin. Pull Request resolved: https://github.com/facebook/yoga/pull/1836 Test Plan: RN ```sh yarn android yarn test-android ``` Yoga ```sh ./gradlew :yoga:assembleDebug ``` Reviewed By: rshest Differential Revision: D79897685 Pulled By: cortinico fbshipit-source-id: 87d2e4b95fbdbfe48d84019e9ffb50deb9286d8c --- java/com/facebook/yoga/LayoutPassReason.java | 43 -------------------- java/com/facebook/yoga/LayoutPassReason.kt | 35 ++++++++++++++++ 2 files changed, 35 insertions(+), 43 deletions(-) delete mode 100644 java/com/facebook/yoga/LayoutPassReason.java create mode 100644 java/com/facebook/yoga/LayoutPassReason.kt diff --git a/java/com/facebook/yoga/LayoutPassReason.java b/java/com/facebook/yoga/LayoutPassReason.java deleted file mode 100644 index 59046f05..00000000 --- a/java/com/facebook/yoga/LayoutPassReason.java +++ /dev/null @@ -1,43 +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. - */ - -package com.facebook.yoga; - -public enum LayoutPassReason { - INITIAL(0), - ABS_LAYOUT(1), - STRETCH(2), - MULTILINE_STRETCH(3), - FLEX_LAYOUT(4), - MEASURE(5), - ABS_MEASURE(6), - FLEX_MEASURE(7); - - private final int mIntValue; - - LayoutPassReason(int intValue) { - mIntValue = intValue; - } - - public int intValue() { - return mIntValue; - } - - public static LayoutPassReason fromInt(int value) { - switch (value) { - case 0: return INITIAL; - case 1: return ABS_LAYOUT; - case 2: return STRETCH; - case 3: return MULTILINE_STRETCH; - case 4: return FLEX_LAYOUT; - case 5: return MEASURE; - case 6: return ABS_MEASURE; - case 7: return FLEX_MEASURE; - default: throw new IllegalArgumentException("Unknown enum value: " + value); - } - } -} diff --git a/java/com/facebook/yoga/LayoutPassReason.kt b/java/com/facebook/yoga/LayoutPassReason.kt new file mode 100644 index 00000000..3c765726 --- /dev/null +++ b/java/com/facebook/yoga/LayoutPassReason.kt @@ -0,0 +1,35 @@ +/* + * 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.yoga + +public enum class LayoutPassReason(public val intValue: Int) { + INITIAL(0), + ABS_LAYOUT(1), + STRETCH(2), + MULTILINE_STRETCH(3), + FLEX_LAYOUT(4), + MEASURE(5), + ABS_MEASURE(6), + FLEX_MEASURE(7); + + public companion object { + @JvmStatic + public fun fromInt(value: Int): LayoutPassReason = + when (value) { + 0 -> INITIAL + 1 -> ABS_LAYOUT + 2 -> STRETCH + 3 -> MULTILINE_STRETCH + 4 -> FLEX_LAYOUT + 5 -> MEASURE + 6 -> ABS_MEASURE + 7 -> FLEX_MEASURE + else -> throw IllegalArgumentException("Unknown enum value: $value") + } + } +} -- 2.50.1.windows.1 From 8087edaafe27123b771ad2c81de2ceda67a85f97 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateo=20Guzm=C3=A1n?= Date: Tue, 12 Aug 2025 09:49:31 -0700 Subject: [PATCH 24/32] Migrate `YogaLayoutType` to Kotlin (#1837) Summary: Migrate com.facebook.yoga.YogaLayoutType to Kotlin. Pull Request resolved: https://github.com/facebook/yoga/pull/1837 Test Plan: RN ```sh yarn android yarn test-android ``` Yoga ```sh ./gradlew :yoga:assembleDebug ``` Reviewed By: rshest Differential Revision: D79897708 Pulled By: cortinico fbshipit-source-id: e3c8a3cc60f806d151d2be956b26dd98963254a6 --- java/com/facebook/yoga/YogaLayoutType.java | 35 ---------------------- java/com/facebook/yoga/YogaLayoutType.kt | 27 +++++++++++++++++ 2 files changed, 27 insertions(+), 35 deletions(-) delete mode 100644 java/com/facebook/yoga/YogaLayoutType.java create mode 100644 java/com/facebook/yoga/YogaLayoutType.kt diff --git a/java/com/facebook/yoga/YogaLayoutType.java b/java/com/facebook/yoga/YogaLayoutType.java deleted file mode 100644 index 8c861ff7..00000000 --- a/java/com/facebook/yoga/YogaLayoutType.java +++ /dev/null @@ -1,35 +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. - */ - -package com.facebook.yoga; - -public enum YogaLayoutType { - LAYOUT(0), - MEASURE(1), - CACHED_LAYOUT(2), - CACHED_MEASURE(3); - - private final int mIntValue; - - YogaLayoutType(int intValue) { - mIntValue = intValue; - } - - public int intValue() { - return mIntValue; - } - - public static YogaLayoutType fromInt(int value) { - switch (value) { - case 0: return LAYOUT; - case 1: return MEASURE; - case 2: return CACHED_LAYOUT; - case 3: return CACHED_MEASURE; - default: throw new IllegalArgumentException("Unknown enum value: " + value); - } - } -} diff --git a/java/com/facebook/yoga/YogaLayoutType.kt b/java/com/facebook/yoga/YogaLayoutType.kt new file mode 100644 index 00000000..6177a412 --- /dev/null +++ b/java/com/facebook/yoga/YogaLayoutType.kt @@ -0,0 +1,27 @@ +/* + * 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.yoga + +public enum class YogaLayoutType(public val intValue: Int) { + LAYOUT(0), + MEASURE(1), + CACHED_LAYOUT(2), + CACHED_MEASURE(3); + + public companion object { + @JvmStatic + public fun fromInt(value: Int): YogaLayoutType = + when (value) { + 0 -> LAYOUT + 1 -> MEASURE + 2 -> CACHED_LAYOUT + 3 -> CACHED_MEASURE + else -> throw IllegalArgumentException("Unknown enum value: $value") + } + } +} -- 2.50.1.windows.1 From 499a825836f3e066162c9f4ca1d27f96028f6563 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateo=20Guzm=C3=A1n?= Date: Tue, 12 Aug 2025 10:54:27 -0700 Subject: [PATCH 25/32] Migrate `DoNotStrip` to Kotlin (#1840) Summary: Migrate com.facebook.yoga.annotations.DoNotStrip to Kotlin. Pull Request resolved: https://github.com/facebook/yoga/pull/1840 Test Plan: RN ```sh yarn android yarn test-android ``` Yoga ```sh ./gradlew :yoga:assembleDebug ``` Reviewed By: rshest Differential Revision: D79897758 Pulled By: cortinico fbshipit-source-id: 79585e6ab793bd72e04440581d866f7721667db3 --- .../facebook/yoga/annotations/DoNotStrip.java | 18 ------------------ .../facebook/yoga/annotations/DoNotStrip.kt | 18 ++++++++++++++++++ 2 files changed, 18 insertions(+), 18 deletions(-) delete mode 100644 java/com/facebook/yoga/annotations/DoNotStrip.java create mode 100644 java/com/facebook/yoga/annotations/DoNotStrip.kt diff --git a/java/com/facebook/yoga/annotations/DoNotStrip.java b/java/com/facebook/yoga/annotations/DoNotStrip.java deleted file mode 100644 index 574d3562..00000000 --- a/java/com/facebook/yoga/annotations/DoNotStrip.java +++ /dev/null @@ -1,18 +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. - */ - -package com.facebook.yoga.annotations; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.Target; - -import static java.lang.annotation.RetentionPolicy.CLASS; - -@Target({ ElementType.TYPE, ElementType.FIELD, ElementType.METHOD, ElementType.CONSTRUCTOR }) -@Retention(CLASS) -public @interface DoNotStrip { } diff --git a/java/com/facebook/yoga/annotations/DoNotStrip.kt b/java/com/facebook/yoga/annotations/DoNotStrip.kt new file mode 100644 index 00000000..c0890371 --- /dev/null +++ b/java/com/facebook/yoga/annotations/DoNotStrip.kt @@ -0,0 +1,18 @@ +/* + * 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.yoga.annotations + +@Target( + AnnotationTarget.CLASS, + AnnotationTarget.FIELD, + AnnotationTarget.FUNCTION, + AnnotationTarget.PROPERTY_GETTER, + AnnotationTarget.PROPERTY_SETTER, + AnnotationTarget.CONSTRUCTOR) +@Retention(AnnotationRetention.BINARY) +public annotation class DoNotStrip -- 2.50.1.windows.1 From bf1cbd29c068f071c41551e3abb3260476576cef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateo=20Guzm=C3=A1n?= Date: Wed, 13 Aug 2025 06:46:48 -0700 Subject: [PATCH 26/32] Migrate `YogaConfigFactory` to Kotlin (#1833) Summary: Migrate com.facebook.yoga.YogaConfigFactory to Kotlin. Pull Request resolved: https://github.com/facebook/yoga/pull/1833 Test Plan: RN ```sh yarn android yarn test-android ``` Yoga ```sh ./gradlew :yoga:assembleDebug ``` Reviewed By: rshest Differential Revision: D79897762 Pulled By: cortinico fbshipit-source-id: 9457b307204f2066a02690f96a88fce6755f915e --- .../yoga/{YogaConfigFactory.java => YogaConfigFactory.kt} | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) rename java/com/facebook/yoga/{YogaConfigFactory.java => YogaConfigFactory.kt} (56%) diff --git a/java/com/facebook/yoga/YogaConfigFactory.java b/java/com/facebook/yoga/YogaConfigFactory.kt similarity index 56% rename from java/com/facebook/yoga/YogaConfigFactory.java rename to java/com/facebook/yoga/YogaConfigFactory.kt index 631545fa..ddee4e60 100644 --- a/java/com/facebook/yoga/YogaConfigFactory.java +++ b/java/com/facebook/yoga/YogaConfigFactory.kt @@ -5,10 +5,8 @@ * LICENSE file in the root directory of this source tree. */ -package com.facebook.yoga; +package com.facebook.yoga -public abstract class YogaConfigFactory { - public static YogaConfig create() { - return new YogaConfigJNIFinalizer(); - } +public object YogaConfigFactory { + @JvmStatic public fun create(): YogaConfig = YogaConfigJNIFinalizer() } -- 2.50.1.windows.1 From c582f7caa6e87bff1ae3dfafadfe38033b2dcaff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateo=20Guzm=C3=A1n?= Date: Wed, 13 Aug 2025 08:56:03 -0700 Subject: [PATCH 27/32] Migrate `YogaNative` to Kotlin (#1839) Summary: Migrate com.facebook.yoga.YogaNative to Kotlin. Pull Request resolved: https://github.com/facebook/yoga/pull/1839 Test Plan: RN ```sh yarn android yarn test-android ``` Yoga ```sh ./gradlew :yoga:assembleDebug ``` Reviewed By: rshest Differential Revision: D79897725 Pulled By: cortinico fbshipit-source-id: 6fc98565368d831b8698464fe26ad47f8fff6a74 --- java/com/facebook/yoga/YogaNative.java | 141 ----------- java/com/facebook/yoga/YogaNative.kt | 331 +++++++++++++++++++++++++ 2 files changed, 331 insertions(+), 141 deletions(-) delete mode 100644 java/com/facebook/yoga/YogaNative.java create mode 100644 java/com/facebook/yoga/YogaNative.kt diff --git a/java/com/facebook/yoga/YogaNative.java b/java/com/facebook/yoga/YogaNative.java deleted file mode 100644 index 8d23257a..00000000 --- a/java/com/facebook/yoga/YogaNative.java +++ /dev/null @@ -1,141 +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. - */ - -package com.facebook.yoga; - -import com.facebook.yoga.annotations.DoNotStrip; -import com.facebook.soloader.SoLoader; - -@DoNotStrip -public class YogaNative { - static { - SoLoader.loadLibrary("yoga"); - } - - // JNI methods that use Vanilla JNI - // YGConfig related - static native long jni_YGConfigNewJNI(); - static native void jni_YGConfigFreeJNI(long nativePointer); - static native void jni_YGConfigSetExperimentalFeatureEnabledJNI(long nativePointer, int feature, boolean enabled); - static native void jni_YGConfigSetUseWebDefaultsJNI(long nativePointer, boolean useWebDefaults); - static native void jni_YGConfigSetPointScaleFactorJNI(long nativePointer, float pixelsInPoint); - static native void jni_YGConfigSetErrataJNI(long nativePointer, int errata); - static native int jni_YGConfigGetErrataJNI(long nativePointer); - static native void jni_YGConfigSetLoggerJNI(long nativePointer, YogaLogger logger); - - // YGNode related - static native long jni_YGNodeNewJNI(); - static native long jni_YGNodeNewWithConfigJNI(long configPointer); - static native void jni_YGNodeFinalizeJNI(long nativePointer); - static native void jni_YGNodeResetJNI(long nativePointer); - static native void jni_YGNodeInsertChildJNI(long nativePointer, long childPointer, int index); - static native void jni_YGNodeSwapChildJNI(long nativePointer, long childPointer, int index); - static native void jni_YGNodeSetIsReferenceBaselineJNI(long nativePointer, boolean isReferenceBaseline); - static native boolean jni_YGNodeIsReferenceBaselineJNI(long nativePointer); - static native void jni_YGNodeRemoveAllChildrenJNI(long nativePointer); - static native void jni_YGNodeRemoveChildJNI(long nativePointer, long childPointer); - static native void jni_YGNodeCalculateLayoutJNI(long nativePointer, float width, float height, long[] nativePointers, YogaNodeJNIBase[] nodes); - static native void jni_YGNodeMarkDirtyJNI(long nativePointer); - static native boolean jni_YGNodeIsDirtyJNI(long nativePointer); - static native void jni_YGNodeCopyStyleJNI(long dstNativePointer, long srcNativePointer); - static native int jni_YGNodeStyleGetDirectionJNI(long nativePointer); - static native void jni_YGNodeStyleSetDirectionJNI(long nativePointer, int direction); - static native int jni_YGNodeStyleGetFlexDirectionJNI(long nativePointer); - static native void jni_YGNodeStyleSetFlexDirectionJNI(long nativePointer, int flexDirection); - static native int jni_YGNodeStyleGetJustifyContentJNI(long nativePointer); - static native void jni_YGNodeStyleSetJustifyContentJNI(long nativePointer, int justifyContent); - static native int jni_YGNodeStyleGetAlignItemsJNI(long nativePointer); - static native void jni_YGNodeStyleSetAlignItemsJNI(long nativePointer, int alignItems); - static native int jni_YGNodeStyleGetAlignSelfJNI(long nativePointer); - static native void jni_YGNodeStyleSetAlignSelfJNI(long nativePointer, int alignSelf); - static native int jni_YGNodeStyleGetAlignContentJNI(long nativePointer); - static native void jni_YGNodeStyleSetAlignContentJNI(long nativePointer, int alignContent); - static native int jni_YGNodeStyleGetPositionTypeJNI(long nativePointer); - static native void jni_YGNodeStyleSetPositionTypeJNI(long nativePointer, int positionType); - static native int jni_YGNodeStyleGetBoxSizingJNI(long nativePointer); - static native void jni_YGNodeStyleSetBoxSizingJNI(long nativePointer, int boxSizing); - static native int jni_YGNodeStyleGetFlexWrapJNI(long nativePointer); - static native void jni_YGNodeStyleSetFlexWrapJNI(long nativePointer, int wrapType); - static native int jni_YGNodeStyleGetOverflowJNI(long nativePointer); - static native void jni_YGNodeStyleSetOverflowJNI(long nativePointer, int overflow); - static native int jni_YGNodeStyleGetDisplayJNI(long nativePointer); - static native void jni_YGNodeStyleSetDisplayJNI(long nativePointer, int display); - static native float jni_YGNodeStyleGetFlexJNI(long nativePointer); - static native void jni_YGNodeStyleSetFlexJNI(long nativePointer, float flex); - static native float jni_YGNodeStyleGetFlexGrowJNI(long nativePointer); - static native void jni_YGNodeStyleSetFlexGrowJNI(long nativePointer, float flexGrow); - static native float jni_YGNodeStyleGetFlexShrinkJNI(long nativePointer); - static native void jni_YGNodeStyleSetFlexShrinkJNI(long nativePointer, float flexShrink); - static native long jni_YGNodeStyleGetFlexBasisJNI(long nativePointer); - static native void jni_YGNodeStyleSetFlexBasisJNI(long nativePointer, float flexBasis); - static native void jni_YGNodeStyleSetFlexBasisPercentJNI(long nativePointer, float percent); - static native void jni_YGNodeStyleSetFlexBasisAutoJNI(long nativePointer); - static native void jni_YGNodeStyleSetFlexBasisMaxContentJNI(long nativePointer); - static native void jni_YGNodeStyleSetFlexBasisFitContentJNI(long nativePointer); - static native void jni_YGNodeStyleSetFlexBasisStretchJNI(long nativePointer); - static native long jni_YGNodeStyleGetMarginJNI(long nativePointer, int edge); - static native void jni_YGNodeStyleSetMarginJNI(long nativePointer, int edge, float margin); - static native void jni_YGNodeStyleSetMarginPercentJNI(long nativePointer, int edge, float percent); - static native void jni_YGNodeStyleSetMarginAutoJNI(long nativePointer, int edge); - static native long jni_YGNodeStyleGetPaddingJNI(long nativePointer, int edge); - static native void jni_YGNodeStyleSetPaddingJNI(long nativePointer, int edge, float padding); - static native void jni_YGNodeStyleSetPaddingPercentJNI(long nativePointer, int edge, float percent); - static native float jni_YGNodeStyleGetBorderJNI(long nativePointer, int edge); - static native void jni_YGNodeStyleSetBorderJNI(long nativePointer, int edge, float border); - static native long jni_YGNodeStyleGetPositionJNI(long nativePointer, int edge); - static native void jni_YGNodeStyleSetPositionJNI(long nativePointer, int edge, float position); - static native void jni_YGNodeStyleSetPositionPercentJNI(long nativePointer, int edge, float percent); - static native void jni_YGNodeStyleSetPositionAutoJNI(long nativePointer, int edge); - static native long jni_YGNodeStyleGetWidthJNI(long nativePointer); - static native void jni_YGNodeStyleSetWidthJNI(long nativePointer, float width); - static native void jni_YGNodeStyleSetWidthPercentJNI(long nativePointer, float percent); - static native void jni_YGNodeStyleSetWidthAutoJNI(long nativePointer); - static native void jni_YGNodeStyleSetWidthMaxContentJNI(long nativePointer); - static native void jni_YGNodeStyleSetWidthFitContentJNI(long nativePointer); - static native void jni_YGNodeStyleSetWidthStretchJNI(long nativePointer); - static native long jni_YGNodeStyleGetHeightJNI(long nativePointer); - static native void jni_YGNodeStyleSetHeightJNI(long nativePointer, float height); - static native void jni_YGNodeStyleSetHeightPercentJNI(long nativePointer, float percent); - static native void jni_YGNodeStyleSetHeightAutoJNI(long nativePointer); - static native void jni_YGNodeStyleSetHeightMaxContentJNI(long nativePointer); - static native void jni_YGNodeStyleSetHeightFitContentJNI(long nativePointer); - static native void jni_YGNodeStyleSetHeightStretchJNI(long nativePointer); - static native long jni_YGNodeStyleGetMinWidthJNI(long nativePointer); - static native void jni_YGNodeStyleSetMinWidthJNI(long nativePointer, float minWidth); - static native void jni_YGNodeStyleSetMinWidthPercentJNI(long nativePointer, float percent); - static native void jni_YGNodeStyleSetMinWidthMaxContentJNI(long nativePointer); - static native void jni_YGNodeStyleSetMinWidthFitContentJNI(long nativePointer); - static native void jni_YGNodeStyleSetMinWidthStretchJNI(long nativePointer); - static native long jni_YGNodeStyleGetMinHeightJNI(long nativePointer); - static native void jni_YGNodeStyleSetMinHeightJNI(long nativePointer, float minHeight); - static native void jni_YGNodeStyleSetMinHeightPercentJNI(long nativePointer, float percent); - static native void jni_YGNodeStyleSetMinHeightMaxContentJNI(long nativePointer); - static native void jni_YGNodeStyleSetMinHeightFitContentJNI(long nativePointer); - static native void jni_YGNodeStyleSetMinHeightStretchJNI(long nativePointer); - static native long jni_YGNodeStyleGetMaxWidthJNI(long nativePointer); - static native void jni_YGNodeStyleSetMaxWidthJNI(long nativePointer, float maxWidth); - static native void jni_YGNodeStyleSetMaxWidthPercentJNI(long nativePointer, float percent); - static native void jni_YGNodeStyleSetMaxWidthMaxContentJNI(long nativePointer); - static native void jni_YGNodeStyleSetMaxWidthFitContentJNI(long nativePointer); - static native void jni_YGNodeStyleSetMaxWidthStretchJNI(long nativePointer); - static native long jni_YGNodeStyleGetMaxHeightJNI(long nativePointer); - static native void jni_YGNodeStyleSetMaxHeightJNI(long nativePointer, float maxheight); - static native void jni_YGNodeStyleSetMaxHeightPercentJNI(long nativePointer, float percent); - static native void jni_YGNodeStyleSetMaxHeightMaxContentJNI(long nativePointer); - static native void jni_YGNodeStyleSetMaxHeightFitContentJNI(long nativePointer); - static native void jni_YGNodeStyleSetMaxHeightStretchJNI(long nativePointer); - static native float jni_YGNodeStyleGetAspectRatioJNI(long nativePointer); - static native void jni_YGNodeStyleSetAspectRatioJNI(long nativePointer, float aspectRatio); - static native long jni_YGNodeStyleGetGapJNI(long nativePointer, int gutter); - static native void jni_YGNodeStyleSetGapJNI(long nativePointer, int gutter, float gapLength); - static native void jni_YGNodeStyleSetGapPercentJNI(long nativePointer, int gutter, float gapLength); - static native void jni_YGNodeSetHasMeasureFuncJNI(long nativePointer, boolean hasMeasureFunc); - static native void jni_YGNodeSetHasBaselineFuncJNI(long nativePointer, boolean hasMeasureFunc); - static native void jni_YGNodeSetStyleInputsJNI(long nativePointer, float[] styleInputsArray, int size); - static native long jni_YGNodeCloneJNI(long nativePointer); - static native void jni_YGNodeSetAlwaysFormsContainingBlockJNI(long nativePointer, boolean alwaysFormContainingBlock); -} diff --git a/java/com/facebook/yoga/YogaNative.kt b/java/com/facebook/yoga/YogaNative.kt new file mode 100644 index 00000000..518326d4 --- /dev/null +++ b/java/com/facebook/yoga/YogaNative.kt @@ -0,0 +1,331 @@ +/* + * 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.yoga + +import com.facebook.soloader.SoLoader +import com.facebook.yoga.annotations.DoNotStrip + +@DoNotStrip +public object YogaNative { + init { + SoLoader.loadLibrary("yoga") + } + + // JNI methods that use Vanilla JNI + // YGConfig related + @JvmStatic public external fun jni_YGConfigNewJNI(): Long + + @JvmStatic public external fun jni_YGConfigFreeJNI(nativePointer: Long) + + @JvmStatic + public external fun jni_YGConfigSetExperimentalFeatureEnabledJNI( + nativePointer: Long, + feature: Int, + enabled: Boolean + ) + + @JvmStatic + public external fun jni_YGConfigSetUseWebDefaultsJNI(nativePointer: Long, useWebDefaults: Boolean) + + @JvmStatic + public external fun jni_YGConfigSetPointScaleFactorJNI(nativePointer: Long, pixelsInPoint: Float) + + @JvmStatic public external fun jni_YGConfigSetErrataJNI(nativePointer: Long, errata: Int) + + @JvmStatic public external fun jni_YGConfigGetErrataJNI(nativePointer: Long): Int + + @JvmStatic public external fun jni_YGConfigSetLoggerJNI(nativePointer: Long, logger: YogaLogger) + + // YGNode related + @JvmStatic public external fun jni_YGNodeNewJNI(): Long + + @JvmStatic public external fun jni_YGNodeNewWithConfigJNI(configPointer: Long): Long + + @JvmStatic public external fun jni_YGNodeFinalizeJNI(nativePointer: Long) + + @JvmStatic public external fun jni_YGNodeResetJNI(nativePointer: Long) + + @JvmStatic + public external fun jni_YGNodeInsertChildJNI(nativePointer: Long, childPointer: Long, index: Int) + + @JvmStatic + public external fun jni_YGNodeSwapChildJNI(nativePointer: Long, childPointer: Long, index: Int) + + @JvmStatic + public external fun jni_YGNodeSetIsReferenceBaselineJNI( + nativePointer: Long, + isReferenceBaseline: Boolean + ) + + @JvmStatic public external fun jni_YGNodeIsReferenceBaselineJNI(nativePointer: Long): Boolean + + @JvmStatic public external fun jni_YGNodeRemoveAllChildrenJNI(nativePointer: Long) + + @JvmStatic public external fun jni_YGNodeRemoveChildJNI(nativePointer: Long, childPointer: Long) + + @JvmStatic + public external fun jni_YGNodeCalculateLayoutJNI( + nativePointer: Long, + width: Float, + height: Float, + nativePointers: LongArray, + nodes: Array + ) + + @JvmStatic public external fun jni_YGNodeMarkDirtyJNI(nativePointer: Long) + + @JvmStatic public external fun jni_YGNodeIsDirtyJNI(nativePointer: Long): Boolean + + @JvmStatic + public external fun jni_YGNodeCopyStyleJNI(dstNativePointer: Long, srcNativePointer: Long) + + @JvmStatic public external fun jni_YGNodeStyleGetDirectionJNI(nativePointer: Long): Int + + @JvmStatic public external fun jni_YGNodeStyleSetDirectionJNI(nativePointer: Long, direction: Int) + + @JvmStatic public external fun jni_YGNodeStyleGetFlexDirectionJNI(nativePointer: Long): Int + + @JvmStatic + public external fun jni_YGNodeStyleSetFlexDirectionJNI(nativePointer: Long, flexDirection: Int) + + @JvmStatic public external fun jni_YGNodeStyleGetJustifyContentJNI(nativePointer: Long): Int + + @JvmStatic + public external fun jni_YGNodeStyleSetJustifyContentJNI(nativePointer: Long, justifyContent: Int) + + @JvmStatic public external fun jni_YGNodeStyleGetAlignItemsJNI(nativePointer: Long): Int + + @JvmStatic + public external fun jni_YGNodeStyleSetAlignItemsJNI(nativePointer: Long, alignItems: Int) + + @JvmStatic public external fun jni_YGNodeStyleGetAlignSelfJNI(nativePointer: Long): Int + + @JvmStatic public external fun jni_YGNodeStyleSetAlignSelfJNI(nativePointer: Long, alignSelf: Int) + + @JvmStatic public external fun jni_YGNodeStyleGetAlignContentJNI(nativePointer: Long): Int + + @JvmStatic + public external fun jni_YGNodeStyleSetAlignContentJNI(nativePointer: Long, alignContent: Int) + + @JvmStatic public external fun jni_YGNodeStyleGetPositionTypeJNI(nativePointer: Long): Int + + @JvmStatic + public external fun jni_YGNodeStyleSetPositionTypeJNI(nativePointer: Long, positionType: Int) + + @JvmStatic public external fun jni_YGNodeStyleGetBoxSizingJNI(nativePointer: Long): Int + + @JvmStatic public external fun jni_YGNodeStyleSetBoxSizingJNI(nativePointer: Long, boxSizing: Int) + + @JvmStatic public external fun jni_YGNodeStyleGetFlexWrapJNI(nativePointer: Long): Int + + @JvmStatic public external fun jni_YGNodeStyleSetFlexWrapJNI(nativePointer: Long, wrapType: Int) + + @JvmStatic public external fun jni_YGNodeStyleGetOverflowJNI(nativePointer: Long): Int + + @JvmStatic public external fun jni_YGNodeStyleSetOverflowJNI(nativePointer: Long, overflow: Int) + + @JvmStatic public external fun jni_YGNodeStyleGetDisplayJNI(nativePointer: Long): Int + + @JvmStatic public external fun jni_YGNodeStyleSetDisplayJNI(nativePointer: Long, display: Int) + + @JvmStatic public external fun jni_YGNodeStyleGetFlexJNI(nativePointer: Long): Float + + @JvmStatic public external fun jni_YGNodeStyleSetFlexJNI(nativePointer: Long, flex: Float) + + @JvmStatic public external fun jni_YGNodeStyleGetFlexGrowJNI(nativePointer: Long): Float + + @JvmStatic public external fun jni_YGNodeStyleSetFlexGrowJNI(nativePointer: Long, flexGrow: Float) + + @JvmStatic public external fun jni_YGNodeStyleGetFlexShrinkJNI(nativePointer: Long): Float + + @JvmStatic + public external fun jni_YGNodeStyleSetFlexShrinkJNI(nativePointer: Long, flexShrink: Float) + + @JvmStatic public external fun jni_YGNodeStyleGetFlexBasisJNI(nativePointer: Long): Long + + @JvmStatic + public external fun jni_YGNodeStyleSetFlexBasisJNI(nativePointer: Long, flexBasis: Float) + + @JvmStatic + public external fun jni_YGNodeStyleSetFlexBasisPercentJNI(nativePointer: Long, percent: Float) + + @JvmStatic public external fun jni_YGNodeStyleSetFlexBasisAutoJNI(nativePointer: Long) + + @JvmStatic public external fun jni_YGNodeStyleSetFlexBasisMaxContentJNI(nativePointer: Long) + + @JvmStatic public external fun jni_YGNodeStyleSetFlexBasisFitContentJNI(nativePointer: Long) + + @JvmStatic public external fun jni_YGNodeStyleSetFlexBasisStretchJNI(nativePointer: Long) + + @JvmStatic public external fun jni_YGNodeStyleGetMarginJNI(nativePointer: Long, edge: Int): Long + + @JvmStatic + public external fun jni_YGNodeStyleSetMarginJNI(nativePointer: Long, edge: Int, margin: Float) + + @JvmStatic + public external fun jni_YGNodeStyleSetMarginPercentJNI( + nativePointer: Long, + edge: Int, + percent: Float + ) + + @JvmStatic public external fun jni_YGNodeStyleSetMarginAutoJNI(nativePointer: Long, edge: Int) + + @JvmStatic public external fun jni_YGNodeStyleGetPaddingJNI(nativePointer: Long, edge: Int): Long + + @JvmStatic + public external fun jni_YGNodeStyleSetPaddingJNI(nativePointer: Long, edge: Int, padding: Float) + + @JvmStatic + public external fun jni_YGNodeStyleSetPaddingPercentJNI( + nativePointer: Long, + edge: Int, + percent: Float + ) + + @JvmStatic public external fun jni_YGNodeStyleGetBorderJNI(nativePointer: Long, edge: Int): Float + + @JvmStatic + public external fun jni_YGNodeStyleSetBorderJNI(nativePointer: Long, edge: Int, border: Float) + + @JvmStatic public external fun jni_YGNodeStyleGetPositionJNI(nativePointer: Long, edge: Int): Long + + @JvmStatic + public external fun jni_YGNodeStyleSetPositionJNI(nativePointer: Long, edge: Int, position: Float) + + @JvmStatic + public external fun jni_YGNodeStyleSetPositionPercentJNI( + nativePointer: Long, + edge: Int, + percent: Float + ) + + @JvmStatic public external fun jni_YGNodeStyleSetPositionAutoJNI(nativePointer: Long, edge: Int) + + @JvmStatic public external fun jni_YGNodeStyleGetWidthJNI(nativePointer: Long): Long + + @JvmStatic public external fun jni_YGNodeStyleSetWidthJNI(nativePointer: Long, width: Float) + + @JvmStatic + public external fun jni_YGNodeStyleSetWidthPercentJNI(nativePointer: Long, percent: Float) + + @JvmStatic public external fun jni_YGNodeStyleSetWidthAutoJNI(nativePointer: Long) + + @JvmStatic public external fun jni_YGNodeStyleSetWidthMaxContentJNI(nativePointer: Long) + + @JvmStatic public external fun jni_YGNodeStyleSetWidthFitContentJNI(nativePointer: Long) + + @JvmStatic public external fun jni_YGNodeStyleSetWidthStretchJNI(nativePointer: Long) + + @JvmStatic public external fun jni_YGNodeStyleGetHeightJNI(nativePointer: Long): Long + + @JvmStatic public external fun jni_YGNodeStyleSetHeightJNI(nativePointer: Long, height: Float) + + @JvmStatic + public external fun jni_YGNodeStyleSetHeightPercentJNI(nativePointer: Long, percent: Float) + + @JvmStatic public external fun jni_YGNodeStyleSetHeightAutoJNI(nativePointer: Long) + + @JvmStatic public external fun jni_YGNodeStyleSetHeightMaxContentJNI(nativePointer: Long) + + @JvmStatic public external fun jni_YGNodeStyleSetHeightFitContentJNI(nativePointer: Long) + + @JvmStatic public external fun jni_YGNodeStyleSetHeightStretchJNI(nativePointer: Long) + + @JvmStatic public external fun jni_YGNodeStyleGetMinWidthJNI(nativePointer: Long): Long + + @JvmStatic public external fun jni_YGNodeStyleSetMinWidthJNI(nativePointer: Long, minWidth: Float) + + @JvmStatic + public external fun jni_YGNodeStyleSetMinWidthPercentJNI(nativePointer: Long, percent: Float) + + @JvmStatic public external fun jni_YGNodeStyleSetMinWidthMaxContentJNI(nativePointer: Long) + + @JvmStatic public external fun jni_YGNodeStyleSetMinWidthFitContentJNI(nativePointer: Long) + + @JvmStatic public external fun jni_YGNodeStyleSetMinWidthStretchJNI(nativePointer: Long) + + @JvmStatic public external fun jni_YGNodeStyleGetMinHeightJNI(nativePointer: Long): Long + + @JvmStatic + public external fun jni_YGNodeStyleSetMinHeightJNI(nativePointer: Long, minHeight: Float) + + @JvmStatic + public external fun jni_YGNodeStyleSetMinHeightPercentJNI(nativePointer: Long, percent: Float) + + @JvmStatic public external fun jni_YGNodeStyleSetMinHeightMaxContentJNI(nativePointer: Long) + + @JvmStatic public external fun jni_YGNodeStyleSetMinHeightFitContentJNI(nativePointer: Long) + + @JvmStatic public external fun jni_YGNodeStyleSetMinHeightStretchJNI(nativePointer: Long) + + @JvmStatic public external fun jni_YGNodeStyleGetMaxWidthJNI(nativePointer: Long): Long + + @JvmStatic public external fun jni_YGNodeStyleSetMaxWidthJNI(nativePointer: Long, maxWidth: Float) + + @JvmStatic + public external fun jni_YGNodeStyleSetMaxWidthPercentJNI(nativePointer: Long, percent: Float) + + @JvmStatic public external fun jni_YGNodeStyleSetMaxWidthMaxContentJNI(nativePointer: Long) + + @JvmStatic public external fun jni_YGNodeStyleSetMaxWidthFitContentJNI(nativePointer: Long) + + @JvmStatic public external fun jni_YGNodeStyleSetMaxWidthStretchJNI(nativePointer: Long) + + @JvmStatic public external fun jni_YGNodeStyleGetMaxHeightJNI(nativePointer: Long): Long + + @JvmStatic + public external fun jni_YGNodeStyleSetMaxHeightJNI(nativePointer: Long, maxheight: Float) + + @JvmStatic + public external fun jni_YGNodeStyleSetMaxHeightPercentJNI(nativePointer: Long, percent: Float) + + @JvmStatic public external fun jni_YGNodeStyleSetMaxHeightMaxContentJNI(nativePointer: Long) + + @JvmStatic public external fun jni_YGNodeStyleSetMaxHeightFitContentJNI(nativePointer: Long) + + @JvmStatic public external fun jni_YGNodeStyleSetMaxHeightStretchJNI(nativePointer: Long) + + @JvmStatic public external fun jni_YGNodeStyleGetAspectRatioJNI(nativePointer: Long): Float + + @JvmStatic + public external fun jni_YGNodeStyleSetAspectRatioJNI(nativePointer: Long, aspectRatio: Float) + + @JvmStatic public external fun jni_YGNodeStyleGetGapJNI(nativePointer: Long, gutter: Int): Long + + @JvmStatic + public external fun jni_YGNodeStyleSetGapJNI(nativePointer: Long, gutter: Int, gapLength: Float) + + @JvmStatic + public external fun jni_YGNodeStyleSetGapPercentJNI( + nativePointer: Long, + gutter: Int, + gapLength: Float + ) + + @JvmStatic + public external fun jni_YGNodeSetHasMeasureFuncJNI(nativePointer: Long, hasMeasureFunc: Boolean) + + @JvmStatic + public external fun jni_YGNodeSetHasBaselineFuncJNI(nativePointer: Long, hasMeasureFunc: Boolean) + + @JvmStatic + public external fun jni_YGNodeSetStyleInputsJNI( + nativePointer: Long, + styleInputsArray: FloatArray, + size: Int + ) + + @JvmStatic public external fun jni_YGNodeCloneJNI(nativePointer: Long): Long + + @JvmStatic + public external fun jni_YGNodeSetAlwaysFormsContainingBlockJNI( + nativePointer: Long, + alwaysFormContainingBlock: Boolean + ) +} -- 2.50.1.windows.1 From 93bea176358580017259ad6690f291d77229782d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateo=20Guzm=C3=A1n?= Date: Wed, 13 Aug 2025 16:45:06 -0700 Subject: [PATCH 28/32] Migrate `YogaValue` to Kotlin (#1838) Summary: Migrate com.facebook.yoga.YogaValue to Kotlin. Pull Request resolved: https://github.com/facebook/yoga/pull/1838 Test Plan: RN ```sh yarn android yarn test-android ``` Yoga ```sh ./gradlew :yoga:assembleDebug ``` Reviewed By: rshest Differential Revision: D79897668 Pulled By: cortinico fbshipit-source-id: dffe2b29087c35e4797f46dea756c51f841590d8 --- java/com/facebook/yoga/YogaValue.java | 80 --------------------------- java/com/facebook/yoga/YogaValue.kt | 66 ++++++++++++++++++++++ 2 files changed, 66 insertions(+), 80 deletions(-) delete mode 100644 java/com/facebook/yoga/YogaValue.java create mode 100644 java/com/facebook/yoga/YogaValue.kt diff --git a/java/com/facebook/yoga/YogaValue.java b/java/com/facebook/yoga/YogaValue.java deleted file mode 100644 index 2a266b02..00000000 --- a/java/com/facebook/yoga/YogaValue.java +++ /dev/null @@ -1,80 +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. - */ - -package com.facebook.yoga; - -public class YogaValue { - static final YogaValue UNDEFINED = new YogaValue(YogaConstants.UNDEFINED, YogaUnit.UNDEFINED); - static final YogaValue ZERO = new YogaValue(0, YogaUnit.POINT); - static final YogaValue AUTO = new YogaValue(YogaConstants.UNDEFINED, YogaUnit.AUTO); - - public final float value; - public final YogaUnit unit; - - public YogaValue(float value, YogaUnit unit) { - this.value = value; - this.unit = unit; - } - - YogaValue(float value, int unit) { - this(value, YogaUnit.fromInt(unit)); - } - - @Override - public boolean equals(Object other) { - if (other instanceof YogaValue) { - final YogaValue otherValue = (YogaValue) other; - if (unit == otherValue.unit) { - return unit == YogaUnit.UNDEFINED - || unit == YogaUnit.AUTO - || Float.compare(value, otherValue.value) == 0; - } - } - return false; - } - - @Override - public int hashCode() { - return Float.floatToIntBits(value) + unit.intValue(); - } - - @Override - public String toString() { - switch (unit) { - case UNDEFINED: - return "undefined"; - case POINT: - return Float.toString(value); - case PERCENT: - return value + "%"; - case AUTO: - return "auto"; - default: - throw new IllegalStateException(); - } - } - - public static YogaValue parse(String s) { - if (s == null) { - return null; - } - - if ("undefined".equals(s)) { - return UNDEFINED; - } - - if ("auto".equals(s)) { - return AUTO; - } - - if (s.endsWith("%")) { - return new YogaValue(Float.parseFloat(s.substring(0, s.length() - 1)), YogaUnit.PERCENT); - } - - return new YogaValue(Float.parseFloat(s), YogaUnit.POINT); - } -} diff --git a/java/com/facebook/yoga/YogaValue.kt b/java/com/facebook/yoga/YogaValue.kt new file mode 100644 index 00000000..ceaf6278 --- /dev/null +++ b/java/com/facebook/yoga/YogaValue.kt @@ -0,0 +1,66 @@ +/* + * 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.yoga + +public class YogaValue +public constructor(@JvmField public val value: Float, @JvmField public val unit: YogaUnit) { + internal constructor(value: Float, unit: Int) : this(value, YogaUnit.fromInt(unit)) + + override fun equals(other: Any?): Boolean { + if (other is YogaValue) { + val otherValue = other + if (unit == otherValue.unit) { + return unit == YogaUnit.UNDEFINED || + unit == YogaUnit.AUTO || + value.compareTo(otherValue.value) == 0 + } + } + return false + } + + override fun hashCode(): Int = java.lang.Float.floatToIntBits(value) + unit.intValue() + + override fun toString(): String = + when (unit) { + YogaUnit.UNDEFINED -> "undefined" + YogaUnit.POINT -> value.toString() + YogaUnit.PERCENT -> "$value%" + YogaUnit.AUTO -> "auto" + else -> throw IllegalStateException() + } + + public companion object { + @JvmField + public val UNDEFINED: YogaValue = YogaValue(YogaConstants.UNDEFINED, YogaUnit.UNDEFINED) + + @JvmField public val ZERO: YogaValue = YogaValue(0f, YogaUnit.POINT) + + @JvmField public val AUTO: YogaValue = YogaValue(YogaConstants.UNDEFINED, YogaUnit.AUTO) + + @JvmStatic + public fun parse(s: String?): YogaValue? { + if (s == null) { + return null + } + + if ("undefined" == s) { + return UNDEFINED + } + + if ("auto" == s) { + return AUTO + } + + if (s.endsWith("%")) { + return YogaValue(s.substring(0, s.length - 1).toFloat(), YogaUnit.PERCENT) + } + + return YogaValue(s.toFloat(), YogaUnit.POINT) + } + } +} -- 2.50.1.windows.1 From d1246f6f0d59fdbf2f2f2fbd6c355b50d6c41318 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nivaldo=20Bondan=C3=A7a?= Date: Thu, 14 Aug 2025 07:24:42 -0700 Subject: [PATCH 29/32] Codemod format for trailing commas incoming change [5/n] (#1847) Summary: X-link: https://github.com/facebook/react-native/pull/53260 Pull Request resolved: https://github.com/facebook/yoga/pull/1847 Adding trailing commas. Reviewed By: cortinico Differential Revision: D80174965 fbshipit-source-id: 5438fa9ebce13525b1286dd30704138ef99703cb --- java/com/facebook/yoga/YogaMeasureFunction.kt | 2 +- java/com/facebook/yoga/annotations/DoNotStrip.kt | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/java/com/facebook/yoga/YogaMeasureFunction.kt b/java/com/facebook/yoga/YogaMeasureFunction.kt index 10b5cfc0..53109a08 100644 --- a/java/com/facebook/yoga/YogaMeasureFunction.kt +++ b/java/com/facebook/yoga/YogaMeasureFunction.kt @@ -14,6 +14,6 @@ public fun interface YogaMeasureFunction { width: Float, widthMode: YogaMeasureMode, height: Float, - heightMode: YogaMeasureMode + heightMode: YogaMeasureMode, ): Long } diff --git a/java/com/facebook/yoga/annotations/DoNotStrip.kt b/java/com/facebook/yoga/annotations/DoNotStrip.kt index c0890371..532bb060 100644 --- a/java/com/facebook/yoga/annotations/DoNotStrip.kt +++ b/java/com/facebook/yoga/annotations/DoNotStrip.kt @@ -13,6 +13,7 @@ package com.facebook.yoga.annotations AnnotationTarget.FUNCTION, AnnotationTarget.PROPERTY_GETTER, AnnotationTarget.PROPERTY_SETTER, - AnnotationTarget.CONSTRUCTOR) + AnnotationTarget.CONSTRUCTOR, +) @Retention(AnnotationRetention.BINARY) public annotation class DoNotStrip -- 2.50.1.windows.1 From 89fc1601515d8686112ec91c0068c7e09e6cc3a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateo=20Guzm=C3=A1n?= Date: Thu, 14 Aug 2025 07:29:26 -0700 Subject: [PATCH 30/32] Migrate `YogaConfig` to Kotlin (#1841) Summary: Migrate com.facebook.yoga.YogaConfig to Kotlin. Pull Request resolved: https://github.com/facebook/yoga/pull/1841 Test Plan: RN ```sh yarn android yarn test-android ``` Yoga ```sh ./gradlew :yoga:assembleDebug ``` Reviewed By: rshest Differential Revision: D79897694 Pulled By: cortinico fbshipit-source-id: 0eff36f47bbb8da6a91087f2ea69bc4e40a732ac --- java/com/facebook/yoga/YogaConfig.java | 29 ---------------------- java/com/facebook/yoga/YogaConfig.kt | 33 ++++++++++++++++++++++++++ 2 files changed, 33 insertions(+), 29 deletions(-) delete mode 100644 java/com/facebook/yoga/YogaConfig.java create mode 100644 java/com/facebook/yoga/YogaConfig.kt diff --git a/java/com/facebook/yoga/YogaConfig.java b/java/com/facebook/yoga/YogaConfig.java deleted file mode 100644 index c841acd7..00000000 --- a/java/com/facebook/yoga/YogaConfig.java +++ /dev/null @@ -1,29 +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. - */ - -package com.facebook.yoga; - -public abstract class YogaConfig { - - public static int SPACING_TYPE = 1; - - public abstract void setExperimentalFeatureEnabled(YogaExperimentalFeature feature, boolean enabled); - - public abstract void setUseWebDefaults(boolean useWebDefaults); - - public abstract void setPointScaleFactor(float pixelsInPoint); - - public abstract void setErrata(YogaErrata errata); - - public abstract YogaErrata getErrata(); - - public abstract void setLogger(YogaLogger logger); - - public abstract YogaLogger getLogger(); - - protected abstract long getNativePointer(); -} diff --git a/java/com/facebook/yoga/YogaConfig.kt b/java/com/facebook/yoga/YogaConfig.kt new file mode 100644 index 00000000..cdf6cfaa --- /dev/null +++ b/java/com/facebook/yoga/YogaConfig.kt @@ -0,0 +1,33 @@ +/* + * 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.yoga + +public abstract class YogaConfig { + public abstract fun setExperimentalFeatureEnabled( + feature: YogaExperimentalFeature, + enabled: Boolean + ) + + public abstract fun setUseWebDefaults(useWebDefaults: Boolean) + + public abstract fun setPointScaleFactor(pixelsInPoint: Float) + + public abstract fun setErrata(errata: YogaErrata) + + public abstract fun getErrata(): YogaErrata + + public abstract fun setLogger(logger: YogaLogger) + + public abstract fun getLogger(): YogaLogger + + protected abstract fun getNativePointer(): Long + + public companion object { + public var SPACING_TYPE: Int = 1 + } +} -- 2.50.1.windows.1 From f16fee8c2e4e9316b6db5d2ab7f7dcfc16bf7be4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nivaldo=20Bondan=C3=A7a?= Date: Mon, 18 Aug 2025 10:24:50 -0700 Subject: [PATCH 31/32] Codemod format for trailing commas incoming change [300/n] (#1848) Summary: Pull Request resolved: https://github.com/facebook/yoga/pull/1848 X-link: https://github.com/facebook/react-native/pull/53338 Adding trailing commas to folders: - xplat/js/react-native-github/packages/react-native - xplat/kotlin/ast_tools/core/src - xplat/kotlin_compiler_plugins/template/src/main - xplat/kotlin/kotlin_multiplatform_template/src/commonMain - xplat/libraries/bloks/bloks-debugging/src - xplat/libraries/bloks/bloks-lispy/src - xplat/libraries/bloks/bloks-step-debugger/src - xplat/mdv/uifiddle-prototype/android-server/playground - xplat/mdv/uifiddle-prototype/android-server/server - xplat/oxygen/common/src/test - xplat/oxygen/mpts/src/main - xplat/oxygen/mpts/src/test - xplat/prototypes/smartglasses/AndroidStudioProjects/MetaAccessoryTest - xplat/prototypes/smartglasses/AndroidStudioProjects/MetaWearableSDKSampleApp - xplat/prototypes/smartglasses/AndroidStudioProjects/MetaWearableSDK - xplat/prototypes/smartglasses/AndroidStudioProjects/Voice - xplat/ReactNative/react-native-cxx/react/renderer - xplat/rtc/media/tools/audio - xplat/security/prodsec/android/codetransparency - xplat/security/prodsec/siggy/java - xplat/simplesql/codegen/java/com - xplat/sonar/android/plugins/jetpack-compose - xplat/sonar/android/plugins/leakcanary2 - xplat/sonar/android/plugins/litho - xplat/sonar/android/plugins/retrofit2-protobuf - xplat/sonar/android/sample/src - xplat/sonar/android/src/facebook Reviewed By: dtolnay Differential Revision: D80452590 fbshipit-source-id: 2bc79edba21e913f6121a25a269c1a4258f5f31c --- java/com/facebook/yoga/YogaConfig.kt | 2 +- java/com/facebook/yoga/YogaNative.kt | 18 +++++++++--------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/java/com/facebook/yoga/YogaConfig.kt b/java/com/facebook/yoga/YogaConfig.kt index cdf6cfaa..764893ff 100644 --- a/java/com/facebook/yoga/YogaConfig.kt +++ b/java/com/facebook/yoga/YogaConfig.kt @@ -10,7 +10,7 @@ package com.facebook.yoga public abstract class YogaConfig { public abstract fun setExperimentalFeatureEnabled( feature: YogaExperimentalFeature, - enabled: Boolean + enabled: Boolean, ) public abstract fun setUseWebDefaults(useWebDefaults: Boolean) diff --git a/java/com/facebook/yoga/YogaNative.kt b/java/com/facebook/yoga/YogaNative.kt index 518326d4..95bf5536 100644 --- a/java/com/facebook/yoga/YogaNative.kt +++ b/java/com/facebook/yoga/YogaNative.kt @@ -26,7 +26,7 @@ public object YogaNative { public external fun jni_YGConfigSetExperimentalFeatureEnabledJNI( nativePointer: Long, feature: Int, - enabled: Boolean + enabled: Boolean, ) @JvmStatic @@ -59,7 +59,7 @@ public object YogaNative { @JvmStatic public external fun jni_YGNodeSetIsReferenceBaselineJNI( nativePointer: Long, - isReferenceBaseline: Boolean + isReferenceBaseline: Boolean, ) @JvmStatic public external fun jni_YGNodeIsReferenceBaselineJNI(nativePointer: Long): Boolean @@ -74,7 +74,7 @@ public object YogaNative { width: Float, height: Float, nativePointers: LongArray, - nodes: Array + nodes: Array, ) @JvmStatic public external fun jni_YGNodeMarkDirtyJNI(nativePointer: Long) @@ -171,7 +171,7 @@ public object YogaNative { public external fun jni_YGNodeStyleSetMarginPercentJNI( nativePointer: Long, edge: Int, - percent: Float + percent: Float, ) @JvmStatic public external fun jni_YGNodeStyleSetMarginAutoJNI(nativePointer: Long, edge: Int) @@ -185,7 +185,7 @@ public object YogaNative { public external fun jni_YGNodeStyleSetPaddingPercentJNI( nativePointer: Long, edge: Int, - percent: Float + percent: Float, ) @JvmStatic public external fun jni_YGNodeStyleGetBorderJNI(nativePointer: Long, edge: Int): Float @@ -202,7 +202,7 @@ public object YogaNative { public external fun jni_YGNodeStyleSetPositionPercentJNI( nativePointer: Long, edge: Int, - percent: Float + percent: Float, ) @JvmStatic public external fun jni_YGNodeStyleSetPositionAutoJNI(nativePointer: Long, edge: Int) @@ -305,7 +305,7 @@ public object YogaNative { public external fun jni_YGNodeStyleSetGapPercentJNI( nativePointer: Long, gutter: Int, - gapLength: Float + gapLength: Float, ) @JvmStatic @@ -318,7 +318,7 @@ public object YogaNative { public external fun jni_YGNodeSetStyleInputsJNI( nativePointer: Long, styleInputsArray: FloatArray, - size: Int + size: Int, ) @JvmStatic public external fun jni_YGNodeCloneJNI(nativePointer: Long): Long @@ -326,6 +326,6 @@ public object YogaNative { @JvmStatic public external fun jni_YGNodeSetAlwaysFormsContainingBlockJNI( nativePointer: Long, - alwaysFormContainingBlock: Boolean + alwaysFormContainingBlock: Boolean, ) } -- 2.50.1.windows.1 From dc2581f229cb05c7d2af8dee37b2ee0b59fd5326 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nivaldo=20Bondan=C3=A7a?= Date: Tue, 19 Aug 2025 18:15:18 -0700 Subject: [PATCH 32/32] Codemod format for trailing commas change Reviewed By: VladimirMakaev Differential Revision: D80576929 fbshipit-source-id: 1310f77f5d9d489b780b14875454ebda7f7adfc9 --- java/build.gradle.kts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/java/build.gradle.kts b/java/build.gradle.kts index 4c73e6ab..21dec6bc 100644 --- a/java/build.gradle.kts +++ b/java/build.gradle.kts @@ -83,7 +83,8 @@ publishing { afterEvaluate { from(components["default"]) } pom { description.set( - "An embeddable and performant flexbox layout engine with bindings for multiple languages") + "An embeddable and performant flexbox layout engine with bindings for multiple languages" + ) name.set(project.name) url.set("https://github.com/facebook/yoga.git") licenses { -- 2.50.1.windows.1