-
Notifications
You must be signed in to change notification settings - Fork 764
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
C++ Cleanup 10/N: YGNodeCalculateLayout
Summary: X-link: facebook/react-native#39195 X-link: facebook/yoga#1352 ## This diff This splits out all of the logic under `YGNodeCalculateLayout` to a couple of different files, does some mechanical renaming, and starts to split up the implementation a tiny bit. After this, core layout functions are all C++ convention and namespaced. Each new file is marked as a move for the sake of blame history. It means Phabricator has a very inaccurate count of lines removed though. ## This stack The organization of the C++ internals of Yoga are in need of attention. 1. Some of the C++ internals are namespaced, but others not. 2. Some of the namespaces include `detail`, but are meant to be used outside of the translation unit (FB Clang Tidy rules warn on any usage of these) 2. Most of the files are in a flat hierarchy, except for event tracing in its own folder 3. Some files and functions begin with YG, others don’t 4. Some functions are uppercase, others are not 5. Almost all of the interesting logic is in Yoga.cpp, and the file is too large to reason about 6. There are multiple grab bag files where folks put random functions they need in (Utils, BitUtils, Yoga-Internal.h) 7. There is no clear indication from file structure or type naming what is private vs not 8. Handles like `YGNodeRef` and `YGConfigRef` can be used to access internals just by importing headers This stack does some much needed spring cleaning: 1. All non-public headers and C++ implementation details are in separate folders from the root level `yoga`. This will give us room to split up logic and add more files without too large a flat hierarchy 3. All private C++ internals are under the `facebook::yoga` namespace. Details namespaces are only ever used within the same header, as they are intended 4. Utils files are split 5. Most C++ internals drop the YG prefix 6. Most C++ internal function names are all lower camel case 7. We start to split up Yoga.cpp 8. Every header beginning with YG or at the top-level directory is public and C only, with the exception of Yoga-Internal.h which has non-public functions for bindings 9. It is not possible to use private APIs without static casting handles to internal classes This will give us more leeway to continue splitting monolithic files, and consistent guidelines for style in new files as well. These changes should not be breaking to any project using only public Yoga headers. This includes every usage of Yoga in fbsource except for RN Fabric which is currently tied to internals. This refactor should make that boundary clearer. Reviewed By: rshest Differential Revision: D48770478 fbshipit-source-id: 2a74b86441c3352de03ae193c98fc3a3573047ed
- Loading branch information
1 parent
c1533a6
commit 6a8fcfb
Showing
15 changed files
with
3,543 additions
and
3,292 deletions.
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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. | ||
*/ | ||
|
||
#pragma once | ||
|
||
#include <yoga/Yoga.h> | ||
|
||
#include <yoga/algorithm/FlexDirection.h> | ||
#include <yoga/node/Node.h> | ||
|
||
namespace facebook::yoga { | ||
|
||
inline YGAlign resolveChildAlignment( | ||
const yoga::Node* node, | ||
const yoga::Node* child) { | ||
const YGAlign align = child->getStyle().alignSelf() == YGAlignAuto | ||
? node->getStyle().alignItems() | ||
: child->getStyle().alignSelf(); | ||
if (align == YGAlignBaseline && isColumn(node->getStyle().flexDirection())) { | ||
return YGAlignFlexStart; | ||
} | ||
return align; | ||
} | ||
|
||
} // namespace facebook::yoga |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
/* | ||
* 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 <yoga/Yoga.h> | ||
|
||
#include <yoga/algorithm/Align.h> | ||
#include <yoga/algorithm/Baseline.h> | ||
#include <yoga/debug/AssertFatal.h> | ||
#include <yoga/event/event.h> | ||
|
||
namespace facebook::yoga { | ||
|
||
float calculateBaseline(const yoga::Node* node, void* layoutContext) { | ||
if (node->hasBaselineFunc()) { | ||
|
||
Event::publish<Event::NodeBaselineStart>(node); | ||
|
||
const float baseline = node->baseline( | ||
node->getLayout().measuredDimensions[YGDimensionWidth], | ||
node->getLayout().measuredDimensions[YGDimensionHeight], | ||
layoutContext); | ||
|
||
Event::publish<Event::NodeBaselineEnd>(node); | ||
|
||
yoga::assertFatalWithNode( | ||
node, | ||
!std::isnan(baseline), | ||
"Expect custom baseline function to not return NaN"); | ||
return baseline; | ||
} | ||
|
||
yoga::Node* baselineChild = nullptr; | ||
const uint32_t childCount = YGNodeGetChildCount(node); | ||
for (uint32_t i = 0; i < childCount; i++) { | ||
auto child = node->getChild(i); | ||
if (child->getLineIndex() > 0) { | ||
break; | ||
} | ||
if (child->getStyle().positionType() == YGPositionTypeAbsolute) { | ||
continue; | ||
} | ||
if (resolveChildAlignment(node, child) == YGAlignBaseline || | ||
child->isReferenceBaseline()) { | ||
baselineChild = child; | ||
break; | ||
} | ||
|
||
if (baselineChild == nullptr) { | ||
baselineChild = child; | ||
} | ||
} | ||
|
||
if (baselineChild == nullptr) { | ||
return node->getLayout().measuredDimensions[YGDimensionHeight]; | ||
} | ||
|
||
const float baseline = calculateBaseline(baselineChild, layoutContext); | ||
return baseline + baselineChild->getLayout().position[YGEdgeTop]; | ||
} | ||
|
||
} // namespace facebook::yoga |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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. | ||
*/ | ||
|
||
#pragma once | ||
|
||
#include <yoga/Yoga.h> | ||
#include <yoga/node/Node.h> | ||
|
||
namespace facebook::yoga { | ||
|
||
// Calculate baseline represented as an offset from the top edge of the node. | ||
float calculateBaseline(const yoga::Node* node, void* layoutContext); | ||
|
||
} // namespace facebook::yoga |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,123 @@ | ||
/* | ||
* 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 <yoga/Yoga.h> | ||
|
||
#include <yoga/algorithm/Cache.h> | ||
#include <yoga/algorithm/PixelGrid.h> | ||
#include <yoga/numeric/Comparison.h> | ||
|
||
namespace facebook::yoga { | ||
|
||
static inline bool sizeIsExactAndMatchesOldMeasuredSize( | ||
YGMeasureMode sizeMode, | ||
float size, | ||
float lastComputedSize) { | ||
return sizeMode == YGMeasureModeExactly && | ||
yoga::inexactEquals(size, lastComputedSize); | ||
} | ||
|
||
static inline bool oldSizeIsUnspecifiedAndStillFits( | ||
YGMeasureMode sizeMode, | ||
float size, | ||
YGMeasureMode lastSizeMode, | ||
float lastComputedSize) { | ||
return sizeMode == YGMeasureModeAtMost && | ||
lastSizeMode == YGMeasureModeUndefined && | ||
(size >= lastComputedSize || yoga::inexactEquals(size, lastComputedSize)); | ||
} | ||
|
||
static inline bool newMeasureSizeIsStricterAndStillValid( | ||
YGMeasureMode sizeMode, | ||
float size, | ||
YGMeasureMode lastSizeMode, | ||
float lastSize, | ||
float lastComputedSize) { | ||
return lastSizeMode == YGMeasureModeAtMost && | ||
sizeMode == YGMeasureModeAtMost && !std::isnan(lastSize) && | ||
!std::isnan(size) && !std::isnan(lastComputedSize) && lastSize > size && | ||
(lastComputedSize <= size || yoga::inexactEquals(size, lastComputedSize)); | ||
} | ||
|
||
bool canUseCachedMeasurement( | ||
const YGMeasureMode widthMode, | ||
const float availableWidth, | ||
const YGMeasureMode heightMode, | ||
const float availableHeight, | ||
const YGMeasureMode lastWidthMode, | ||
const float lastAvailableWidth, | ||
const YGMeasureMode lastHeightMode, | ||
const float lastAvailableHeight, | ||
const float lastComputedWidth, | ||
const float lastComputedHeight, | ||
const float marginRow, | ||
const float marginColumn, | ||
const yoga::Config* const config) { | ||
if ((!std::isnan(lastComputedHeight) && lastComputedHeight < 0) || | ||
(!std::isnan(lastComputedWidth) && lastComputedWidth < 0)) { | ||
return false; | ||
} | ||
|
||
const float pointScaleFactor = config->getPointScaleFactor(); | ||
|
||
bool useRoundedComparison = config != nullptr && pointScaleFactor != 0; | ||
const float effectiveWidth = useRoundedComparison | ||
? roundValueToPixelGrid(availableWidth, pointScaleFactor, false, false) | ||
: availableWidth; | ||
const float effectiveHeight = useRoundedComparison | ||
? roundValueToPixelGrid(availableHeight, pointScaleFactor, false, false) | ||
: availableHeight; | ||
const float effectiveLastWidth = useRoundedComparison | ||
? roundValueToPixelGrid( | ||
lastAvailableWidth, pointScaleFactor, false, false) | ||
: lastAvailableWidth; | ||
const float effectiveLastHeight = useRoundedComparison | ||
? roundValueToPixelGrid( | ||
lastAvailableHeight, pointScaleFactor, false, false) | ||
: lastAvailableHeight; | ||
|
||
const bool hasSameWidthSpec = lastWidthMode == widthMode && | ||
yoga::inexactEquals(effectiveLastWidth, effectiveWidth); | ||
const bool hasSameHeightSpec = lastHeightMode == heightMode && | ||
yoga::inexactEquals(effectiveLastHeight, effectiveHeight); | ||
|
||
const bool widthIsCompatible = | ||
hasSameWidthSpec || | ||
sizeIsExactAndMatchesOldMeasuredSize( | ||
widthMode, availableWidth - marginRow, lastComputedWidth) || | ||
oldSizeIsUnspecifiedAndStillFits( | ||
widthMode, | ||
availableWidth - marginRow, | ||
lastWidthMode, | ||
lastComputedWidth) || | ||
newMeasureSizeIsStricterAndStillValid( | ||
widthMode, | ||
availableWidth - marginRow, | ||
lastWidthMode, | ||
lastAvailableWidth, | ||
lastComputedWidth); | ||
|
||
const bool heightIsCompatible = | ||
hasSameHeightSpec || | ||
sizeIsExactAndMatchesOldMeasuredSize( | ||
heightMode, availableHeight - marginColumn, lastComputedHeight) || | ||
oldSizeIsUnspecifiedAndStillFits( | ||
heightMode, | ||
availableHeight - marginColumn, | ||
lastHeightMode, | ||
lastComputedHeight) || | ||
newMeasureSizeIsStricterAndStillValid( | ||
heightMode, | ||
availableHeight - marginColumn, | ||
lastHeightMode, | ||
lastAvailableHeight, | ||
lastComputedHeight); | ||
|
||
return widthIsCompatible && heightIsCompatible; | ||
} | ||
|
||
} // namespace facebook::yoga |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
/* | ||
* Copyright (c) Meta Platforms, Inc. and affiliates. | ||
* | ||
* This source code is licensed under the MIT license found in the | ||
* LICENSE file in the root directory of this source tree. | ||
*/ | ||
|
||
#pragma once | ||
|
||
#include <yoga/Yoga.h> | ||
#include <yoga/config/Config.h> | ||
|
||
namespace facebook::yoga { | ||
|
||
bool canUseCachedMeasurement( | ||
YGMeasureMode widthMode, | ||
float availableWidth, | ||
YGMeasureMode heightMode, | ||
float availableHeight, | ||
YGMeasureMode lastWidthMode, | ||
float lastAvailableWidth, | ||
YGMeasureMode lastHeightMode, | ||
float lastAvailableHeight, | ||
float lastComputedWidth, | ||
float lastComputedHeight, | ||
float marginRow, | ||
float marginColumn, | ||
const yoga::Config* config); | ||
|
||
} // namespace facebook::yoga |
Oops, something went wrong.