Revert D48712710: C++ Cleanup 3/N: Reorganize YGNode

Differential Revision:
D48712710

Original commit changeset: d28eae38469a

Original Phabricator Diff: D48712710

fbshipit-source-id: 7a10b071edcf045ce98bbf8f9deca0d0e2e80a14
This commit is contained in:
Zhiyao Zhou
2023-08-29 23:27:25 -07:00
committed by Facebook GitHub Bot
parent 6ca56e87ce
commit ea7f61a3db
31 changed files with 578 additions and 625 deletions

View File

@@ -1,44 +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.
*/
#include <yoga/node/LayoutResults.h>
#include <yoga/Utils.h>
namespace facebook::yoga {
bool LayoutResults::operator==(LayoutResults layout) const {
bool isEqual = YGFloatArrayEqual(position, layout.position) &&
YGFloatArrayEqual(dimensions, layout.dimensions) &&
YGFloatArrayEqual(margin, layout.margin) &&
YGFloatArrayEqual(border, layout.border) &&
YGFloatArrayEqual(padding, layout.padding) &&
direction() == layout.direction() &&
hadOverflow() == layout.hadOverflow() &&
lastOwnerDirection == layout.lastOwnerDirection &&
nextCachedMeasurementsIndex == layout.nextCachedMeasurementsIndex &&
cachedLayout == layout.cachedLayout &&
computedFlexBasis == layout.computedFlexBasis;
for (uint32_t i = 0; i < YG_MAX_CACHED_RESULT_COUNT && isEqual; ++i) {
isEqual = isEqual && cachedMeasurements[i] == layout.cachedMeasurements[i];
}
if (!yoga::isUndefined(measuredDimensions[0]) ||
!yoga::isUndefined(layout.measuredDimensions[0])) {
isEqual =
isEqual && (measuredDimensions[0] == layout.measuredDimensions[0]);
}
if (!yoga::isUndefined(measuredDimensions[1]) ||
!yoga::isUndefined(layout.measuredDimensions[1])) {
isEqual =
isEqual && (measuredDimensions[1] == layout.measuredDimensions[1]);
}
return isEqual;
}
} // namespace facebook::yoga

View File

@@ -1,67 +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.
*/
#pragma once
#include <yoga/BitUtils.h>
#include <yoga/YGFloatOptional.h>
#include <yoga/Yoga-internal.h>
namespace facebook::yoga {
struct LayoutResults {
std::array<float, 4> position = {};
std::array<float, 2> dimensions = {{YGUndefined, YGUndefined}};
std::array<float, 4> margin = {};
std::array<float, 4> border = {};
std::array<float, 4> padding = {};
private:
static constexpr size_t directionOffset = 0;
static constexpr size_t hadOverflowOffset =
directionOffset + facebook::yoga::detail::bitWidthFn<YGDirection>();
uint8_t flags = 0;
public:
uint32_t computedFlexBasisGeneration = 0;
YGFloatOptional computedFlexBasis = {};
// Instead of recomputing the entire layout every single time, we cache some
// information to break early when nothing changed
uint32_t generationCount = 0;
YGDirection lastOwnerDirection = YGDirectionInherit;
uint32_t nextCachedMeasurementsIndex = 0;
std::array<YGCachedMeasurement, YG_MAX_CACHED_RESULT_COUNT>
cachedMeasurements = {};
std::array<float, 2> measuredDimensions = {{YGUndefined, YGUndefined}};
YGCachedMeasurement cachedLayout = YGCachedMeasurement();
YGDirection direction() const {
return facebook::yoga::detail::getEnumData<YGDirection>(
flags, directionOffset);
}
void setDirection(YGDirection direction) {
facebook::yoga::detail::setEnumData<YGDirection>(
flags, directionOffset, direction);
}
bool hadOverflow() const {
return facebook::yoga::detail::getBooleanData(flags, hadOverflowOffset);
}
void setHadOverflow(bool hadOverflow) {
facebook::yoga::detail::setBooleanData(
flags, hadOverflowOffset, hadOverflow);
}
bool operator==(LayoutResults layout) const;
bool operator!=(LayoutResults layout) const { return !(*this == layout); }
};
} // namespace facebook::yoga

View File

@@ -1,583 +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.
*/
#include <yoga/node/Node.h>
#include <algorithm>
#include <iostream>
#include <yoga/Utils.h>
namespace facebook::yoga {
Node::Node(yoga::Config* config) : config_{config} {
YGAssert(config != nullptr, "Attempting to construct Node with null config");
flags_.hasNewLayout = true;
if (config->useWebDefaults()) {
useWebDefaults();
}
}
Node::Node(Node&& 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 Node::print(void* printContext) {
if (print_.noContext != nullptr) {
if (flags_.printUsesContext) {
print_.withContext(this, printContext);
} else {
print_.noContext(this);
}
}
}
CompactValue Node::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 Node::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 Node::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 Node::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 Node::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 Node::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 Node::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 Node::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 Node::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 Node::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 Node::getMarginForAxis(
const YGFlexDirection axis,
const float widthSize) const {
return getLeadingMargin(axis, widthSize) + getTrailingMargin(axis, widthSize);
}
YGFloatOptional Node::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 Node::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 Node::baseline(float width, float height, void* layoutContext) {
return flags_.baselineUsesContext
? baseline_.withContext(this, width, height, layoutContext)
: baseline_.noContext(this, width, height);
}
// Setters
void Node::setMeasureFunc(decltype(Node::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 Node::setMeasureFunc(YGMeasureFunc measureFunc) {
flags_.measureUsesContext = false;
decltype(Node::measure_) m;
m.noContext = measureFunc;
setMeasureFunc(m);
}
YOGA_EXPORT void Node::setMeasureFunc(MeasureWithContextFn measureFunc) {
flags_.measureUsesContext = true;
decltype(Node::measure_) m;
m.withContext = measureFunc;
setMeasureFunc(m);
}
void Node::replaceChild(Node* child, uint32_t index) {
children_[index] = child;
}
void Node::replaceChild(Node* oldChild, Node* newChild) {
std::replace(children_.begin(), children_.end(), oldChild, newChild);
}
void Node::insertChild(Node* child, uint32_t index) {
children_.insert(children_.begin() + index, child);
}
void Node::setConfig(yoga::Config* config) {
YGAssert(config != nullptr, "Attempting to set a null config on a Node");
YGAssertWithConfig(
config,
config->useWebDefaults() == config_->useWebDefaults(),
"UseWebDefaults may not be changed after constructing a Node");
if (yoga::configUpdateInvalidatesLayout(config_, config)) {
markDirtyAndPropagate();
}
config_ = config;
}
void Node::setDirty(bool isDirty) {
if (isDirty == flags_.isDirty) {
return;
}
flags_.isDirty = isDirty;
if (isDirty && dirtied_) {
dirtied_(this);
}
}
bool Node::removeChild(Node* child) {
std::vector<Node*>::iterator p =
std::find(children_.begin(), children_.end(), child);
if (p != children_.end()) {
children_.erase(p);
return true;
}
return false;
}
void Node::removeChild(uint32_t index) {
children_.erase(children_.begin() + index);
}
void Node::setLayoutDirection(YGDirection direction) {
layout_.setDirection(direction);
}
void Node::setLayoutMargin(float margin, int index) {
layout_.margin[index] = margin;
}
void Node::setLayoutBorder(float border, int index) {
layout_.border[index] = border;
}
void Node::setLayoutPadding(float padding, int index) {
layout_.padding[index] = padding;
}
void Node::setLayoutLastOwnerDirection(YGDirection direction) {
layout_.lastOwnerDirection = direction;
}
void Node::setLayoutComputedFlexBasis(const YGFloatOptional computedFlexBasis) {
layout_.computedFlexBasis = computedFlexBasis;
}
void Node::setLayoutPosition(float position, int index) {
layout_.position[index] = position;
}
void Node::setLayoutComputedFlexBasisGeneration(
uint32_t computedFlexBasisGeneration) {
layout_.computedFlexBasisGeneration = computedFlexBasisGeneration;
}
void Node::setLayoutMeasuredDimension(float measuredDimension, int index) {
layout_.measuredDimensions[index] = measuredDimension;
}
void Node::setLayoutHadOverflow(bool hadOverflow) {
layout_.setHadOverflow(hadOverflow);
}
void Node::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 Node::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 Node::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 Node::marginLeadingValue(const YGFlexDirection axis) const {
if (YGFlexDirectionIsRow(axis) &&
!style_.margin()[YGEdgeStart].isUndefined()) {
return style_.margin()[YGEdgeStart];
} else {
return style_.margin()[leading[axis]];
}
}
YGValue Node::marginTrailingValue(const YGFlexDirection axis) const {
if (YGFlexDirectionIsRow(axis) && !style_.margin()[YGEdgeEnd].isUndefined()) {
return style_.margin()[YGEdgeEnd];
} else {
return style_.margin()[trailing[axis]];
}
}
YGValue Node::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 Node::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 Node::resolveDirection(const YGDirection ownerDirection) {
if (style_.direction() == YGDirectionInherit) {
return ownerDirection > YGDirectionInherit ? ownerDirection
: YGDirectionLTR;
} else {
return style_.direction();
}
}
YOGA_EXPORT void Node::clearChildren() {
children_.clear();
children_.shrink_to_fit();
}
// Other Methods
void Node::cloneChildrenIfNeeded(void* cloneContext) {
iterChildrenAfterCloningIfNeeded([](Node*, void*) {}, cloneContext);
}
void Node::markDirtyAndPropagate() {
if (!flags_.isDirty) {
setDirty(true);
setLayoutComputedFlexBasis(YGFloatOptional());
if (owner_) {
owner_->markDirtyAndPropagate();
}
}
}
void Node::markDirtyAndPropagateDownwards() {
flags_.isDirty = true;
for_each(children_.begin(), children_.end(), [](Node* childNode) {
childNode->markDirtyAndPropagateDownwards();
});
}
float Node::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 Node::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 Node::isNodeFlexible() {
return (
(style_.positionType() != YGPositionTypeAbsolute) &&
(resolveFlexGrow() != 0 || resolveFlexShrink() != 0));
}
float Node::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 Node::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 Node::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 Node::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 Node::getLeadingPaddingAndBorder(
const YGFlexDirection axis,
const float widthSize) const {
return getLeadingPadding(axis, widthSize) +
YGFloatOptional(getLeadingBorder(axis));
}
YGFloatOptional Node::getTrailingPaddingAndBorder(
const YGFlexDirection axis,
const float widthSize) const {
return getTrailingPadding(axis, widthSize) +
YGFloatOptional(getTrailingBorder(axis));
}
void Node::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 = Node{getConfig()};
}
} // namespace facebook::yoga

View File

@@ -1,343 +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.
*/
#pragma once
#include <cstdint>
#include <stdio.h>
#include <yoga/config/Config.h>
#include <yoga/node/LayoutResults.h>
#include <yoga/Yoga-internal.h>
#include <yoga/style/CompactValue.h>
#include <yoga/style/Style.h>
// Tag struct used to form the opaque YGNodeRef for the public C API
struct YGNode {};
namespace facebook::yoga {
#pragma pack(push)
#pragma pack(1)
struct NodeFlags {
bool hasNewLayout : 1;
bool isReferenceBaseline : 1;
bool isDirty : 1;
uint8_t nodeType : 1;
bool measureUsesContext : 1;
bool baselineUsesContext : 1;
bool printUsesContext : 1;
};
#pragma pack(pop)
class YOGA_EXPORT Node : public ::YGNode {
public:
using MeasureWithContextFn =
YGSize (*)(YGNode*, float, YGMeasureMode, float, YGMeasureMode, void*);
using BaselineWithContextFn = float (*)(YGNode*, float, float, void*);
using PrintWithContextFn = void (*)(YGNode*, void*);
private:
void* context_ = nullptr;
NodeFlags flags_ = {};
union {
YGMeasureFunc noContext;
MeasureWithContextFn withContext;
} measure_ = {nullptr};
union {
YGBaselineFunc noContext;
BaselineWithContextFn withContext;
} baseline_ = {nullptr};
union {
YGPrintFunc noContext;
PrintWithContextFn withContext;
} print_ = {nullptr};
YGDirtiedFunc dirtied_ = nullptr;
Style style_ = {};
LayoutResults layout_ = {};
uint32_t lineIndex_ = 0;
Node* owner_ = nullptr;
std::vector<Node*> children_ = {};
Config* config_;
std::array<YGValue, 2> resolvedDimensions_ = {
{YGValueUndefined, YGValueUndefined}};
YGFloatOptional relativePosition(
const YGFlexDirection axis,
const float axisSize) const;
void setMeasureFunc(decltype(measure_));
void setBaselineFunc(decltype(baseline_));
void useWebDefaults() {
style_.flexDirection() = YGFlexDirectionRow;
style_.alignContent() = YGAlignStretch;
}
// DANGER DANGER DANGER!
// If the node assigned to has children, we'd either have to deallocate
// them (potentially incorrect) or ignore them (danger of leaks). Only ever
// use this after checking that there are no children.
// DO NOT CHANGE THE VISIBILITY OF THIS METHOD!
Node& operator=(Node&&) = default;
public:
Node() : Node{static_cast<Config*>(YGConfigGetDefault())} {
flags_.hasNewLayout = true;
}
explicit Node(Config* config);
~Node() = default; // cleanup of owner/children relationships in YGNodeFree
Node(Node&&);
// Does not expose true value semantics, as children are not cloned eagerly.
// Should we remove this?
Node(const Node& node) = default;
// assignment means potential leaks of existing children, or alternatively
// freeing unowned memory, double free, or freeing stack memory.
Node& operator=(const Node&) = delete;
// Getters
void* getContext() const { return context_; }
void print(void*);
bool getHasNewLayout() const { return flags_.hasNewLayout; }
YGNodeType getNodeType() const {
return static_cast<YGNodeType>(flags_.nodeType);
}
bool hasMeasureFunc() const noexcept { return measure_.noContext != nullptr; }
YGSize measure(float, YGMeasureMode, float, YGMeasureMode, void*);
bool hasBaselineFunc() const noexcept {
return baseline_.noContext != nullptr;
}
float baseline(float width, float height, void* layoutContext);
bool hasErrata(YGErrata errata) const { return config_->hasErrata(errata); }
YGDirtiedFunc getDirtied() const { return dirtied_; }
// For Performance reasons passing as reference.
Style& getStyle() { return style_; }
const Style& getStyle() const { return style_; }
// For Performance reasons passing as reference.
LayoutResults& getLayout() { return layout_; }
const LayoutResults& getLayout() const { return layout_; }
uint32_t getLineIndex() const { return lineIndex_; }
bool isReferenceBaseline() { return flags_.isReferenceBaseline; }
// returns the Node that owns this Node. An owner is used to identify
// the YogaTree that a Node belongs to. This method will return the parent
// of the Node when a Node only belongs to one YogaTree or nullptr when
// the Node is shared between two or more YogaTrees.
Node* getOwner() const { return owner_; }
// Deprecated, use getOwner() instead.
Node* getParent() const { return getOwner(); }
const std::vector<Node*>& getChildren() const { return children_; }
// Applies a callback to all children, after cloning them if they are not
// owned.
template <typename T>
void iterChildrenAfterCloningIfNeeded(T callback, void* cloneContext) {
int i = 0;
for (Node*& child : children_) {
if (child->getOwner() != this) {
child = static_cast<Node*>(
config_->cloneNode(child, this, i, cloneContext));
child->setOwner(this);
}
i += 1;
callback(child, cloneContext);
}
}
Node* getChild(uint32_t index) const { return children_.at(index); }
Config* getConfig() const { return config_; }
bool isDirty() const { return flags_.isDirty; }
std::array<YGValue, 2> getResolvedDimensions() const {
return resolvedDimensions_;
}
YGValue getResolvedDimension(int index) const {
return resolvedDimensions_[index];
}
static CompactValue computeEdgeValueForColumn(
const Style::Edges& edges,
YGEdge edge,
CompactValue defaultValue);
static CompactValue computeEdgeValueForRow(
const Style::Edges& edges,
YGEdge rowEdge,
YGEdge edge,
CompactValue defaultValue);
static CompactValue computeRowGap(
const Style::Gutters& gutters,
CompactValue defaultValue);
static CompactValue computeColumnGap(
const Style::Gutters& gutters,
CompactValue defaultValue);
// Methods related to positions, margin, padding and border
YGFloatOptional getLeadingPosition(
const YGFlexDirection axis,
const float axisSize) const;
bool isLeadingPositionDefined(const YGFlexDirection axis) const;
bool isTrailingPosDefined(const YGFlexDirection axis) const;
YGFloatOptional getTrailingPosition(
const YGFlexDirection axis,
const float axisSize) const;
YGFloatOptional getLeadingMargin(
const YGFlexDirection axis,
const float widthSize) const;
YGFloatOptional getTrailingMargin(
const YGFlexDirection axis,
const float widthSize) const;
float getLeadingBorder(const YGFlexDirection flexDirection) const;
float getTrailingBorder(const YGFlexDirection flexDirection) const;
YGFloatOptional getLeadingPadding(
const YGFlexDirection axis,
const float widthSize) const;
YGFloatOptional getTrailingPadding(
const YGFlexDirection axis,
const float widthSize) const;
YGFloatOptional getLeadingPaddingAndBorder(
const YGFlexDirection axis,
const float widthSize) const;
YGFloatOptional getTrailingPaddingAndBorder(
const YGFlexDirection axis,
const float widthSize) const;
YGFloatOptional getMarginForAxis(
const YGFlexDirection axis,
const float widthSize) const;
YGFloatOptional getGapForAxis(
const YGFlexDirection axis,
const float widthSize) const;
// Setters
void setContext(void* context) { context_ = context; }
void setPrintFunc(YGPrintFunc printFunc) {
print_.noContext = printFunc;
flags_.printUsesContext = false;
}
void setPrintFunc(PrintWithContextFn printFunc) {
print_.withContext = printFunc;
flags_.printUsesContext = true;
}
void setPrintFunc(std::nullptr_t) { setPrintFunc(YGPrintFunc{nullptr}); }
void setHasNewLayout(bool hasNewLayout) {
flags_.hasNewLayout = hasNewLayout;
}
void setNodeType(YGNodeType nodeType) {
flags_.nodeType = static_cast<uint8_t>(nodeType);
}
void setMeasureFunc(YGMeasureFunc measureFunc);
void setMeasureFunc(MeasureWithContextFn);
void setMeasureFunc(std::nullptr_t) {
return setMeasureFunc(YGMeasureFunc{nullptr});
}
void setBaselineFunc(YGBaselineFunc baseLineFunc) {
flags_.baselineUsesContext = false;
baseline_.noContext = baseLineFunc;
}
void setBaselineFunc(BaselineWithContextFn baseLineFunc) {
flags_.baselineUsesContext = true;
baseline_.withContext = baseLineFunc;
}
void setBaselineFunc(std::nullptr_t) {
return setBaselineFunc(YGBaselineFunc{nullptr});
}
void setDirtiedFunc(YGDirtiedFunc dirtiedFunc) { dirtied_ = dirtiedFunc; }
void setStyle(const Style& style) { style_ = style; }
void setLayout(const LayoutResults& layout) { layout_ = layout; }
void setLineIndex(uint32_t lineIndex) { lineIndex_ = lineIndex; }
void setIsReferenceBaseline(bool isReferenceBaseline) {
flags_.isReferenceBaseline = isReferenceBaseline;
}
void setOwner(Node* owner) { owner_ = owner; }
void setChildren(const std::vector<Node*>& children) { children_ = children; }
// TODO: rvalue override for setChildren
void setConfig(Config* config);
void setDirty(bool isDirty);
void setLayoutLastOwnerDirection(YGDirection direction);
void setLayoutComputedFlexBasis(const YGFloatOptional computedFlexBasis);
void setLayoutComputedFlexBasisGeneration(
uint32_t computedFlexBasisGeneration);
void setLayoutMeasuredDimension(float measuredDimension, int index);
void setLayoutHadOverflow(bool hadOverflow);
void setLayoutDimension(float dimension, int index);
void setLayoutDirection(YGDirection direction);
void setLayoutMargin(float margin, int index);
void setLayoutBorder(float border, int index);
void setLayoutPadding(float padding, int index);
void setLayoutPosition(float position, int index);
void setPosition(
const YGDirection direction,
const float mainSize,
const float crossSize,
const float ownerWidth);
void markDirtyAndPropagateDownwards();
// Other methods
YGValue marginLeadingValue(const YGFlexDirection axis) const;
YGValue marginTrailingValue(const YGFlexDirection axis) const;
YGValue resolveFlexBasisPtr() const;
void resolveDimension();
YGDirection resolveDirection(const YGDirection ownerDirection);
void clearChildren();
/// Replaces the occurrences of oldChild with newChild
void replaceChild(Node* oldChild, Node* newChild);
void replaceChild(Node* child, uint32_t index);
void insertChild(Node* child, uint32_t index);
/// Removes the first occurrence of child
bool removeChild(Node* child);
void removeChild(uint32_t index);
void cloneChildrenIfNeeded(void*);
void markDirtyAndPropagate();
float resolveFlexGrow() const;
float resolveFlexShrink() const;
bool isNodeFlexible();
void reset();
};
} // namespace facebook::yoga