Summary: X-link: https://github.com/facebook/react-native/pull/39221 Pull Request resolved: https://github.com/facebook/yoga/pull/1349 X-link: https://github.com/facebook/react-native/pull/39171 ## This diff This diff adds a `style` directory for code related to storing and manipulating styles. `YGStyle`, which is not a public API, is renamed to `yoga::Style` and moved into this folder, alongside `CompactValue`. We will eventually add `ValuePool` alongside this for the next generation style representation. ## 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. Changelog: [Internal] Reviewed By: shwanton Differential Revision: D48847261 fbshipit-source-id: 0fc8c6991e19079f3f0d55d368574757e453fe93
586 lines
17 KiB
C++
586 lines
17 KiB
C++
/*
|
|
* 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 "YGNode.h"
|
|
#include <algorithm>
|
|
#include <iostream>
|
|
#include "Utils.h"
|
|
|
|
using namespace facebook;
|
|
using namespace facebook::yoga;
|
|
using facebook::yoga::CompactValue;
|
|
|
|
YGNode::YGNode(const YGConfigRef config) : config_{config} {
|
|
YGAssert(
|
|
config != nullptr, "Attempting to construct YGNode with null config");
|
|
|
|
flags_.hasNewLayout = true;
|
|
if (config->useWebDefaults()) {
|
|
useWebDefaults();
|
|
}
|
|
}
|
|
|
|
YGNode::YGNode(YGNode&& node) {
|
|
context_ = node.context_;
|
|
flags_ = node.flags_;
|
|
measure_ = node.measure_;
|
|
baseline_ = node.baseline_;
|
|
print_ = node.print_;
|
|
dirtied_ = node.dirtied_;
|
|
style_ = node.style_;
|
|
layout_ = node.layout_;
|
|
lineIndex_ = node.lineIndex_;
|
|
owner_ = node.owner_;
|
|
children_ = std::move(node.children_);
|
|
config_ = node.config_;
|
|
resolvedDimensions_ = node.resolvedDimensions_;
|
|
for (auto c : children_) {
|
|
c->setOwner(this);
|
|
}
|
|
}
|
|
|
|
void YGNode::print(void* printContext) {
|
|
if (print_.noContext != nullptr) {
|
|
if (flags_.printUsesContext) {
|
|
print_.withContext(this, printContext);
|
|
} else {
|
|
print_.noContext(this);
|
|
}
|
|
}
|
|
}
|
|
|
|
CompactValue YGNode::computeEdgeValueForRow(
|
|
const Style::Edges& edges,
|
|
YGEdge rowEdge,
|
|
YGEdge edge,
|
|
CompactValue defaultValue) {
|
|
if (!edges[rowEdge].isUndefined()) {
|
|
return edges[rowEdge];
|
|
} else if (!edges[edge].isUndefined()) {
|
|
return edges[edge];
|
|
} else if (!edges[YGEdgeHorizontal].isUndefined()) {
|
|
return edges[YGEdgeHorizontal];
|
|
} else if (!edges[YGEdgeAll].isUndefined()) {
|
|
return edges[YGEdgeAll];
|
|
} else {
|
|
return defaultValue;
|
|
}
|
|
}
|
|
|
|
CompactValue YGNode::computeEdgeValueForColumn(
|
|
const Style::Edges& edges,
|
|
YGEdge edge,
|
|
CompactValue defaultValue) {
|
|
if (!edges[edge].isUndefined()) {
|
|
return edges[edge];
|
|
} else if (!edges[YGEdgeVertical].isUndefined()) {
|
|
return edges[YGEdgeVertical];
|
|
} else if (!edges[YGEdgeAll].isUndefined()) {
|
|
return edges[YGEdgeAll];
|
|
} else {
|
|
return defaultValue;
|
|
}
|
|
}
|
|
|
|
CompactValue YGNode::computeRowGap(
|
|
const Style::Gutters& gutters,
|
|
CompactValue defaultValue) {
|
|
if (!gutters[YGGutterRow].isUndefined()) {
|
|
return gutters[YGGutterRow];
|
|
} else if (!gutters[YGGutterAll].isUndefined()) {
|
|
return gutters[YGGutterAll];
|
|
} else {
|
|
return defaultValue;
|
|
}
|
|
}
|
|
|
|
CompactValue YGNode::computeColumnGap(
|
|
const Style::Gutters& gutters,
|
|
CompactValue defaultValue) {
|
|
if (!gutters[YGGutterColumn].isUndefined()) {
|
|
return gutters[YGGutterColumn];
|
|
} else if (!gutters[YGGutterAll].isUndefined()) {
|
|
return gutters[YGGutterAll];
|
|
} else {
|
|
return defaultValue;
|
|
}
|
|
}
|
|
|
|
YGFloatOptional YGNode::getLeadingPosition(
|
|
const YGFlexDirection axis,
|
|
const float axisSize) const {
|
|
auto leadingPosition = YGFlexDirectionIsRow(axis)
|
|
? computeEdgeValueForRow(
|
|
style_.position(),
|
|
YGEdgeStart,
|
|
leading[axis],
|
|
CompactValue::ofZero())
|
|
: computeEdgeValueForColumn(
|
|
style_.position(), leading[axis], CompactValue::ofZero());
|
|
return YGResolveValue(leadingPosition, axisSize);
|
|
}
|
|
|
|
YGFloatOptional YGNode::getTrailingPosition(
|
|
const YGFlexDirection axis,
|
|
const float axisSize) const {
|
|
auto trailingPosition = YGFlexDirectionIsRow(axis)
|
|
? computeEdgeValueForRow(
|
|
style_.position(),
|
|
YGEdgeEnd,
|
|
trailing[axis],
|
|
CompactValue::ofZero())
|
|
: computeEdgeValueForColumn(
|
|
style_.position(), trailing[axis], CompactValue::ofZero());
|
|
return YGResolveValue(trailingPosition, axisSize);
|
|
}
|
|
|
|
bool YGNode::isLeadingPositionDefined(const YGFlexDirection axis) const {
|
|
auto leadingPosition = YGFlexDirectionIsRow(axis)
|
|
? computeEdgeValueForRow(
|
|
style_.position(),
|
|
YGEdgeStart,
|
|
leading[axis],
|
|
CompactValue::ofUndefined())
|
|
: computeEdgeValueForColumn(
|
|
style_.position(), leading[axis], CompactValue::ofUndefined());
|
|
return !leadingPosition.isUndefined();
|
|
}
|
|
|
|
bool YGNode::isTrailingPosDefined(const YGFlexDirection axis) const {
|
|
auto trailingPosition = YGFlexDirectionIsRow(axis)
|
|
? computeEdgeValueForRow(
|
|
style_.position(),
|
|
YGEdgeEnd,
|
|
trailing[axis],
|
|
CompactValue::ofUndefined())
|
|
: computeEdgeValueForColumn(
|
|
style_.position(), trailing[axis], CompactValue::ofUndefined());
|
|
return !trailingPosition.isUndefined();
|
|
}
|
|
|
|
YGFloatOptional YGNode::getLeadingMargin(
|
|
const YGFlexDirection axis,
|
|
const float widthSize) const {
|
|
auto leadingMargin = YGFlexDirectionIsRow(axis)
|
|
? computeEdgeValueForRow(
|
|
style_.margin(), YGEdgeStart, leading[axis], CompactValue::ofZero())
|
|
: computeEdgeValueForColumn(
|
|
style_.margin(), leading[axis], CompactValue::ofZero());
|
|
return YGResolveValueMargin(leadingMargin, widthSize);
|
|
}
|
|
|
|
YGFloatOptional YGNode::getTrailingMargin(
|
|
const YGFlexDirection axis,
|
|
const float widthSize) const {
|
|
auto trailingMargin = YGFlexDirectionIsRow(axis)
|
|
? computeEdgeValueForRow(
|
|
style_.margin(), YGEdgeEnd, trailing[axis], CompactValue::ofZero())
|
|
: computeEdgeValueForColumn(
|
|
style_.margin(), trailing[axis], CompactValue::ofZero());
|
|
return YGResolveValueMargin(trailingMargin, widthSize);
|
|
}
|
|
|
|
YGFloatOptional YGNode::getMarginForAxis(
|
|
const YGFlexDirection axis,
|
|
const float widthSize) const {
|
|
return getLeadingMargin(axis, widthSize) + getTrailingMargin(axis, widthSize);
|
|
}
|
|
|
|
YGFloatOptional YGNode::getGapForAxis(
|
|
const YGFlexDirection axis,
|
|
const float widthSize) const {
|
|
auto gap = YGFlexDirectionIsRow(axis)
|
|
? computeColumnGap(style_.gap(), CompactValue::ofZero())
|
|
: computeRowGap(style_.gap(), CompactValue::ofZero());
|
|
return YGResolveValue(gap, widthSize);
|
|
}
|
|
|
|
YGSize YGNode::measure(
|
|
float width,
|
|
YGMeasureMode widthMode,
|
|
float height,
|
|
YGMeasureMode heightMode,
|
|
void* layoutContext) {
|
|
return flags_.measureUsesContext
|
|
? measure_.withContext(
|
|
this, width, widthMode, height, heightMode, layoutContext)
|
|
: measure_.noContext(this, width, widthMode, height, heightMode);
|
|
}
|
|
|
|
float YGNode::baseline(float width, float height, void* layoutContext) {
|
|
return flags_.baselineUsesContext
|
|
? baseline_.withContext(this, width, height, layoutContext)
|
|
: baseline_.noContext(this, width, height);
|
|
}
|
|
|
|
// Setters
|
|
|
|
void YGNode::setMeasureFunc(decltype(YGNode::measure_) measureFunc) {
|
|
if (measureFunc.noContext == nullptr) {
|
|
// TODO: t18095186 Move nodeType to opt-in function and mark appropriate
|
|
// places in Litho
|
|
setNodeType(YGNodeTypeDefault);
|
|
} else {
|
|
YGAssertWithNode(
|
|
this,
|
|
children_.size() == 0,
|
|
"Cannot set measure function: Nodes with measure functions cannot have "
|
|
"children.");
|
|
// TODO: t18095186 Move nodeType to opt-in function and mark appropriate
|
|
// places in Litho
|
|
setNodeType(YGNodeTypeText);
|
|
}
|
|
|
|
measure_ = measureFunc;
|
|
}
|
|
|
|
void YGNode::setMeasureFunc(YGMeasureFunc measureFunc) {
|
|
flags_.measureUsesContext = false;
|
|
decltype(YGNode::measure_) m;
|
|
m.noContext = measureFunc;
|
|
setMeasureFunc(m);
|
|
}
|
|
|
|
YOGA_EXPORT void YGNode::setMeasureFunc(MeasureWithContextFn measureFunc) {
|
|
flags_.measureUsesContext = true;
|
|
decltype(YGNode::measure_) m;
|
|
m.withContext = measureFunc;
|
|
setMeasureFunc(m);
|
|
}
|
|
|
|
void YGNode::replaceChild(YGNodeRef child, uint32_t index) {
|
|
children_[index] = child;
|
|
}
|
|
|
|
void YGNode::replaceChild(YGNodeRef oldChild, YGNodeRef newChild) {
|
|
std::replace(children_.begin(), children_.end(), oldChild, newChild);
|
|
}
|
|
|
|
void YGNode::insertChild(YGNodeRef child, uint32_t index) {
|
|
children_.insert(children_.begin() + index, child);
|
|
}
|
|
|
|
void YGNode::setConfig(YGConfigRef config) {
|
|
YGAssert(config != nullptr, "Attempting to set a null config on a YGNode");
|
|
YGAssertWithConfig(
|
|
config,
|
|
config->useWebDefaults() == config_->useWebDefaults(),
|
|
"UseWebDefaults may not be changed after constructing a YGNode");
|
|
|
|
if (yoga::configUpdateInvalidatesLayout(config_, config)) {
|
|
markDirtyAndPropagate();
|
|
}
|
|
|
|
config_ = config;
|
|
}
|
|
|
|
void YGNode::setDirty(bool isDirty) {
|
|
if (isDirty == flags_.isDirty) {
|
|
return;
|
|
}
|
|
flags_.isDirty = isDirty;
|
|
if (isDirty && dirtied_) {
|
|
dirtied_(this);
|
|
}
|
|
}
|
|
|
|
bool YGNode::removeChild(YGNodeRef child) {
|
|
std::vector<YGNodeRef>::iterator p =
|
|
std::find(children_.begin(), children_.end(), child);
|
|
if (p != children_.end()) {
|
|
children_.erase(p);
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void YGNode::removeChild(uint32_t index) {
|
|
children_.erase(children_.begin() + index);
|
|
}
|
|
|
|
void YGNode::setLayoutDirection(YGDirection direction) {
|
|
layout_.setDirection(direction);
|
|
}
|
|
|
|
void YGNode::setLayoutMargin(float margin, int index) {
|
|
layout_.margin[index] = margin;
|
|
}
|
|
|
|
void YGNode::setLayoutBorder(float border, int index) {
|
|
layout_.border[index] = border;
|
|
}
|
|
|
|
void YGNode::setLayoutPadding(float padding, int index) {
|
|
layout_.padding[index] = padding;
|
|
}
|
|
|
|
void YGNode::setLayoutLastOwnerDirection(YGDirection direction) {
|
|
layout_.lastOwnerDirection = direction;
|
|
}
|
|
|
|
void YGNode::setLayoutComputedFlexBasis(
|
|
const YGFloatOptional computedFlexBasis) {
|
|
layout_.computedFlexBasis = computedFlexBasis;
|
|
}
|
|
|
|
void YGNode::setLayoutPosition(float position, int index) {
|
|
layout_.position[index] = position;
|
|
}
|
|
|
|
void YGNode::setLayoutComputedFlexBasisGeneration(
|
|
uint32_t computedFlexBasisGeneration) {
|
|
layout_.computedFlexBasisGeneration = computedFlexBasisGeneration;
|
|
}
|
|
|
|
void YGNode::setLayoutMeasuredDimension(float measuredDimension, int index) {
|
|
layout_.measuredDimensions[index] = measuredDimension;
|
|
}
|
|
|
|
void YGNode::setLayoutHadOverflow(bool hadOverflow) {
|
|
layout_.setHadOverflow(hadOverflow);
|
|
}
|
|
|
|
void YGNode::setLayoutDimension(float dimension, int index) {
|
|
layout_.dimensions[index] = dimension;
|
|
}
|
|
|
|
// If both left and right are defined, then use left. Otherwise return +left or
|
|
// -right depending on which is defined.
|
|
YGFloatOptional YGNode::relativePosition(
|
|
const YGFlexDirection axis,
|
|
const float axisSize) const {
|
|
if (isLeadingPositionDefined(axis)) {
|
|
return getLeadingPosition(axis, axisSize);
|
|
}
|
|
|
|
YGFloatOptional trailingPosition = getTrailingPosition(axis, axisSize);
|
|
if (!trailingPosition.isUndefined()) {
|
|
trailingPosition = YGFloatOptional{-1 * trailingPosition.unwrap()};
|
|
}
|
|
return trailingPosition;
|
|
}
|
|
|
|
void YGNode::setPosition(
|
|
const YGDirection direction,
|
|
const float mainSize,
|
|
const float crossSize,
|
|
const float ownerWidth) {
|
|
/* Root nodes should be always layouted as LTR, so we don't return negative
|
|
* values. */
|
|
const YGDirection directionRespectingRoot =
|
|
owner_ != nullptr ? direction : YGDirectionLTR;
|
|
const YGFlexDirection mainAxis =
|
|
YGResolveFlexDirection(style_.flexDirection(), directionRespectingRoot);
|
|
const YGFlexDirection crossAxis =
|
|
YGFlexDirectionCross(mainAxis, directionRespectingRoot);
|
|
|
|
// Here we should check for `YGPositionTypeStatic` and in this case zero inset
|
|
// properties (left, right, top, bottom, begin, end).
|
|
// https://www.w3.org/TR/css-position-3/#valdef-position-static
|
|
const YGFloatOptional relativePositionMain =
|
|
relativePosition(mainAxis, mainSize);
|
|
const YGFloatOptional relativePositionCross =
|
|
relativePosition(crossAxis, crossSize);
|
|
|
|
setLayoutPosition(
|
|
(getLeadingMargin(mainAxis, ownerWidth) + relativePositionMain).unwrap(),
|
|
leading[mainAxis]);
|
|
setLayoutPosition(
|
|
(getTrailingMargin(mainAxis, ownerWidth) + relativePositionMain).unwrap(),
|
|
trailing[mainAxis]);
|
|
setLayoutPosition(
|
|
(getLeadingMargin(crossAxis, ownerWidth) + relativePositionCross)
|
|
.unwrap(),
|
|
leading[crossAxis]);
|
|
setLayoutPosition(
|
|
(getTrailingMargin(crossAxis, ownerWidth) + relativePositionCross)
|
|
.unwrap(),
|
|
trailing[crossAxis]);
|
|
}
|
|
|
|
YGValue YGNode::marginLeadingValue(const YGFlexDirection axis) const {
|
|
if (YGFlexDirectionIsRow(axis) &&
|
|
!style_.margin()[YGEdgeStart].isUndefined()) {
|
|
return style_.margin()[YGEdgeStart];
|
|
} else {
|
|
return style_.margin()[leading[axis]];
|
|
}
|
|
}
|
|
|
|
YGValue YGNode::marginTrailingValue(const YGFlexDirection axis) const {
|
|
if (YGFlexDirectionIsRow(axis) && !style_.margin()[YGEdgeEnd].isUndefined()) {
|
|
return style_.margin()[YGEdgeEnd];
|
|
} else {
|
|
return style_.margin()[trailing[axis]];
|
|
}
|
|
}
|
|
|
|
YGValue YGNode::resolveFlexBasisPtr() const {
|
|
YGValue flexBasis = style_.flexBasis();
|
|
if (flexBasis.unit != YGUnitAuto && flexBasis.unit != YGUnitUndefined) {
|
|
return flexBasis;
|
|
}
|
|
if (!style_.flex().isUndefined() && style_.flex().unwrap() > 0.0f) {
|
|
return config_->useWebDefaults() ? YGValueAuto : YGValueZero;
|
|
}
|
|
return YGValueAuto;
|
|
}
|
|
|
|
void YGNode::resolveDimension() {
|
|
using namespace yoga;
|
|
const Style& style = getStyle();
|
|
for (auto dim : {YGDimensionWidth, YGDimensionHeight}) {
|
|
if (!style.maxDimensions()[dim].isUndefined() &&
|
|
YGValueEqual(style.maxDimensions()[dim], style.minDimensions()[dim])) {
|
|
resolvedDimensions_[dim] = style.maxDimensions()[dim];
|
|
} else {
|
|
resolvedDimensions_[dim] = style.dimensions()[dim];
|
|
}
|
|
}
|
|
}
|
|
|
|
YGDirection YGNode::resolveDirection(const YGDirection ownerDirection) {
|
|
if (style_.direction() == YGDirectionInherit) {
|
|
return ownerDirection > YGDirectionInherit ? ownerDirection
|
|
: YGDirectionLTR;
|
|
} else {
|
|
return style_.direction();
|
|
}
|
|
}
|
|
|
|
YOGA_EXPORT void YGNode::clearChildren() {
|
|
children_.clear();
|
|
children_.shrink_to_fit();
|
|
}
|
|
|
|
// Other Methods
|
|
|
|
void YGNode::cloneChildrenIfNeeded(void* cloneContext) {
|
|
iterChildrenAfterCloningIfNeeded([](YGNodeRef, void*) {}, cloneContext);
|
|
}
|
|
|
|
void YGNode::markDirtyAndPropagate() {
|
|
if (!flags_.isDirty) {
|
|
setDirty(true);
|
|
setLayoutComputedFlexBasis(YGFloatOptional());
|
|
if (owner_) {
|
|
owner_->markDirtyAndPropagate();
|
|
}
|
|
}
|
|
}
|
|
|
|
void YGNode::markDirtyAndPropagateDownwards() {
|
|
flags_.isDirty = true;
|
|
for_each(children_.begin(), children_.end(), [](YGNodeRef childNode) {
|
|
childNode->markDirtyAndPropagateDownwards();
|
|
});
|
|
}
|
|
|
|
float YGNode::resolveFlexGrow() const {
|
|
// Root nodes flexGrow should always be 0
|
|
if (owner_ == nullptr) {
|
|
return 0.0;
|
|
}
|
|
if (!style_.flexGrow().isUndefined()) {
|
|
return style_.flexGrow().unwrap();
|
|
}
|
|
if (!style_.flex().isUndefined() && style_.flex().unwrap() > 0.0f) {
|
|
return style_.flex().unwrap();
|
|
}
|
|
return kDefaultFlexGrow;
|
|
}
|
|
|
|
float YGNode::resolveFlexShrink() const {
|
|
if (owner_ == nullptr) {
|
|
return 0.0;
|
|
}
|
|
if (!style_.flexShrink().isUndefined()) {
|
|
return style_.flexShrink().unwrap();
|
|
}
|
|
if (!config_->useWebDefaults() && !style_.flex().isUndefined() &&
|
|
style_.flex().unwrap() < 0.0f) {
|
|
return -style_.flex().unwrap();
|
|
}
|
|
return config_->useWebDefaults() ? kWebDefaultFlexShrink : kDefaultFlexShrink;
|
|
}
|
|
|
|
bool YGNode::isNodeFlexible() {
|
|
return (
|
|
(style_.positionType() != YGPositionTypeAbsolute) &&
|
|
(resolveFlexGrow() != 0 || resolveFlexShrink() != 0));
|
|
}
|
|
|
|
float YGNode::getLeadingBorder(const YGFlexDirection axis) const {
|
|
YGValue leadingBorder = YGFlexDirectionIsRow(axis)
|
|
? computeEdgeValueForRow(
|
|
style_.border(), YGEdgeStart, leading[axis], CompactValue::ofZero())
|
|
: computeEdgeValueForColumn(
|
|
style_.border(), leading[axis], CompactValue::ofZero());
|
|
return fmaxf(leadingBorder.value, 0.0f);
|
|
}
|
|
|
|
float YGNode::getTrailingBorder(const YGFlexDirection axis) const {
|
|
YGValue trailingBorder = YGFlexDirectionIsRow(axis)
|
|
? computeEdgeValueForRow(
|
|
style_.border(), YGEdgeEnd, trailing[axis], CompactValue::ofZero())
|
|
: computeEdgeValueForColumn(
|
|
style_.border(), trailing[axis], CompactValue::ofZero());
|
|
return fmaxf(trailingBorder.value, 0.0f);
|
|
}
|
|
|
|
YGFloatOptional YGNode::getLeadingPadding(
|
|
const YGFlexDirection axis,
|
|
const float widthSize) const {
|
|
auto leadingPadding = YGFlexDirectionIsRow(axis)
|
|
? computeEdgeValueForRow(
|
|
style_.padding(),
|
|
YGEdgeStart,
|
|
leading[axis],
|
|
CompactValue::ofZero())
|
|
: computeEdgeValueForColumn(
|
|
style_.padding(), leading[axis], CompactValue::ofZero());
|
|
return YGFloatOptionalMax(
|
|
YGResolveValue(leadingPadding, widthSize), YGFloatOptional(0.0f));
|
|
}
|
|
|
|
YGFloatOptional YGNode::getTrailingPadding(
|
|
const YGFlexDirection axis,
|
|
const float widthSize) const {
|
|
auto trailingPadding = YGFlexDirectionIsRow(axis)
|
|
? computeEdgeValueForRow(
|
|
style_.padding(), YGEdgeEnd, trailing[axis], CompactValue::ofZero())
|
|
: computeEdgeValueForColumn(
|
|
style_.padding(), trailing[axis], CompactValue::ofZero());
|
|
return YGFloatOptionalMax(
|
|
YGResolveValue(trailingPadding, widthSize), YGFloatOptional(0.0f));
|
|
}
|
|
|
|
YGFloatOptional YGNode::getLeadingPaddingAndBorder(
|
|
const YGFlexDirection axis,
|
|
const float widthSize) const {
|
|
return getLeadingPadding(axis, widthSize) +
|
|
YGFloatOptional(getLeadingBorder(axis));
|
|
}
|
|
|
|
YGFloatOptional YGNode::getTrailingPaddingAndBorder(
|
|
const YGFlexDirection axis,
|
|
const float widthSize) const {
|
|
return getTrailingPadding(axis, widthSize) +
|
|
YGFloatOptional(getTrailingBorder(axis));
|
|
}
|
|
|
|
void YGNode::reset() {
|
|
YGAssertWithNode(
|
|
this,
|
|
children_.size() == 0,
|
|
"Cannot reset a node which still has children attached");
|
|
YGAssertWithNode(
|
|
this, owner_ == nullptr, "Cannot reset a node still attached to a owner");
|
|
|
|
*this = YGNode{getConfig()};
|
|
}
|