123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587 |
- /**
- * Copyright (c) Facebook, Inc. and its 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 "CompactValue.h"
- #include "Utils.h"
- using namespace facebook;
- using facebook::yoga::detail::CompactValue;
- YGNode::YGNode(YGNode&& node) {
- context_ = node.context_;
- hasNewLayout_ = node.hasNewLayout_;
- isReferenceBaseline_ = node.isReferenceBaseline_;
- isDirty_ = node.isDirty_;
- nodeType_ = node.nodeType_;
- measureUsesContext_ = node.measureUsesContext_;
- baselineUsesContext_ = node.baselineUsesContext_;
- printUsesContext_ = node.printUsesContext_;
- 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(c);
- }
- }
- void YGNode::print(void* printContext) {
- if (print_.noContext != nullptr) {
- if (printUsesContext_) {
- print_.withContext(this, printContext);
- } else {
- print_.noContext(this);
- }
- }
- }
- YGFloatOptional YGNode::getLeadingPosition(
- const YGFlexDirection axis,
- const float axisSize) const {
- if (YGFlexDirectionIsRow(axis)) {
- auto leadingPosition = YGComputedEdgeValue(
- style_.position, YGEdgeStart, CompactValue::ofUndefined());
- if (!leadingPosition.isUndefined()) {
- return YGResolveValue(leadingPosition, axisSize);
- }
- }
- auto leadingPosition = YGComputedEdgeValue(
- style_.position, leading[axis], CompactValue::ofUndefined());
- return leadingPosition.isUndefined()
- ? YGFloatOptional{0}
- : YGResolveValue(leadingPosition, axisSize);
- }
- YGFloatOptional YGNode::getTrailingPosition(
- const YGFlexDirection axis,
- const float axisSize) const {
- if (YGFlexDirectionIsRow(axis)) {
- auto trailingPosition = YGComputedEdgeValue(
- style_.position, YGEdgeEnd, CompactValue::ofUndefined());
- if (!trailingPosition.isUndefined()) {
- return YGResolveValue(trailingPosition, axisSize);
- }
- }
- auto trailingPosition = YGComputedEdgeValue(
- style_.position, trailing[axis], CompactValue::ofUndefined());
- return trailingPosition.isUndefined()
- ? YGFloatOptional{0}
- : YGResolveValue(trailingPosition, axisSize);
- }
- bool YGNode::isLeadingPositionDefined(const YGFlexDirection axis) const {
- return (YGFlexDirectionIsRow(axis) &&
- !YGComputedEdgeValue(
- style_.position, YGEdgeStart, CompactValue::ofUndefined())
- .isUndefined()) ||
- !YGComputedEdgeValue(
- style_.position, leading[axis], CompactValue::ofUndefined())
- .isUndefined();
- }
- bool YGNode::isTrailingPosDefined(const YGFlexDirection axis) const {
- return (YGFlexDirectionIsRow(axis) &&
- !YGComputedEdgeValue(
- style_.position, YGEdgeEnd, CompactValue::ofUndefined())
- .isUndefined()) ||
- !YGComputedEdgeValue(
- style_.position, trailing[axis], CompactValue::ofUndefined())
- .isUndefined();
- }
- YGFloatOptional YGNode::getLeadingMargin(
- const YGFlexDirection axis,
- const float widthSize) const {
- if (YGFlexDirectionIsRow(axis) && !style_.margin[YGEdgeStart].isUndefined()) {
- return YGResolveValueMargin(style_.margin[YGEdgeStart], widthSize);
- }
- return YGResolveValueMargin(
- YGComputedEdgeValue(style_.margin, leading[axis], CompactValue::ofZero()),
- widthSize);
- }
- YGFloatOptional YGNode::getTrailingMargin(
- const YGFlexDirection axis,
- const float widthSize) const {
- if (YGFlexDirectionIsRow(axis) && !style_.margin[YGEdgeEnd].isUndefined()) {
- return YGResolveValueMargin(style_.margin[YGEdgeEnd], widthSize);
- }
- return YGResolveValueMargin(
- YGComputedEdgeValue(
- style_.margin, trailing[axis], CompactValue::ofZero()),
- widthSize);
- }
- YGFloatOptional YGNode::getMarginForAxis(
- const YGFlexDirection axis,
- const float widthSize) const {
- return getLeadingMargin(axis, widthSize) + getTrailingMargin(axis, widthSize);
- }
- YGSize YGNode::measure(
- float width,
- YGMeasureMode widthMode,
- float height,
- YGMeasureMode heightMode,
- void* layoutContext) {
- return 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 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
- nodeType_ = 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) {
- measureUsesContext_ = false;
- decltype(YGNode::measure_) m;
- m.noContext = measureFunc;
- setMeasureFunc(m);
- }
- void YGNode::setMeasureFunc(MeasureWithContextFn measureFunc) {
- 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::setDirty(bool isDirty) {
- if (isDirty == isDirty_) {
- return;
- }
- 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_.direction = 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_.hadOverflow = 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);
- 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;
- for (int dim = YGDimensionWidth; dim < enums::count<YGDimension>(); dim++) {
- if (!getStyle().maxDimensions[dim].isUndefined() &&
- YGValueEqual(
- getStyle().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;
- }
- }
- void YGNode::clearChildren() {
- children_.clear();
- children_.shrink_to_fit();
- }
- // Other Methods
- void YGNode::cloneChildrenIfNeeded(void* cloneContext) {
- iterChildrenAfterCloningIfNeeded([](YGNodeRef, void*) {}, cloneContext);
- }
- void YGNode::markDirtyAndPropogate() {
- if (!isDirty_) {
- setDirty(true);
- setLayoutComputedFlexBasis(YGFloatOptional());
- if (owner_) {
- owner_->markDirtyAndPropogate();
- }
- }
- }
- void YGNode::markDirtyAndPropogateDownwards() {
- isDirty_ = true;
- for_each(children_.begin(), children_.end(), [](YGNodeRef childNode) {
- childNode->markDirtyAndPropogateDownwards();
- });
- }
- float YGNode::resolveFlexGrow() {
- // 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() {
- 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 == YGPositionTypeRelative) &&
- (resolveFlexGrow() != 0 || resolveFlexShrink() != 0));
- }
- float YGNode::getLeadingBorder(const YGFlexDirection axis) const {
- YGValue leadingBorder;
- if (YGFlexDirectionIsRow(axis) && !style_.border[YGEdgeStart].isUndefined()) {
- leadingBorder = style_.border[YGEdgeStart];
- if (leadingBorder.value >= 0) {
- return leadingBorder.value;
- }
- }
- leadingBorder =
- YGComputedEdgeValue(style_.border, leading[axis], CompactValue::ofZero());
- return YGFloatMax(leadingBorder.value, 0.0f);
- }
- float YGNode::getTrailingBorder(const YGFlexDirection flexDirection) const {
- YGValue trailingBorder;
- if (YGFlexDirectionIsRow(flexDirection) &&
- !style_.border[YGEdgeEnd].isUndefined()) {
- trailingBorder = style_.border[YGEdgeEnd];
- if (trailingBorder.value >= 0.0f) {
- return trailingBorder.value;
- }
- }
- trailingBorder = YGComputedEdgeValue(
- style_.border, trailing[flexDirection], CompactValue::ofZero());
- return YGFloatMax(trailingBorder.value, 0.0f);
- }
- YGFloatOptional YGNode::getLeadingPadding(
- const YGFlexDirection axis,
- const float widthSize) const {
- const YGFloatOptional paddingEdgeStart =
- YGResolveValue(style_.padding[YGEdgeStart], widthSize);
- if (YGFlexDirectionIsRow(axis) &&
- !style_.padding[YGEdgeStart].isUndefined() &&
- !paddingEdgeStart.isUndefined() && paddingEdgeStart.unwrap() >= 0.0f) {
- return paddingEdgeStart;
- }
- YGFloatOptional resolvedValue = YGResolveValue(
- YGComputedEdgeValue(
- style_.padding, leading[axis], CompactValue::ofZero()),
- widthSize);
- return YGFloatOptionalMax(resolvedValue, YGFloatOptional(0.0f));
- }
- YGFloatOptional YGNode::getTrailingPadding(
- const YGFlexDirection axis,
- const float widthSize) const {
- const YGFloatOptional paddingEdgeEnd =
- YGResolveValue(style_.padding[YGEdgeEnd], widthSize);
- if (YGFlexDirectionIsRow(axis) && paddingEdgeEnd >= YGFloatOptional{0.0f}) {
- return paddingEdgeEnd;
- }
- YGFloatOptional resolvedValue = YGResolveValue(
- YGComputedEdgeValue(
- style_.padding, trailing[axis], CompactValue::ofZero()),
- widthSize);
- return YGFloatOptionalMax(resolvedValue, 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));
- }
- bool YGNode::didUseLegacyFlag() {
- bool didUseLegacyFlag = layout_.didUseLegacyFlag;
- if (didUseLegacyFlag) {
- return true;
- }
- for (const auto& child : children_) {
- if (child->layout_.didUseLegacyFlag) {
- didUseLegacyFlag = true;
- break;
- }
- }
- return didUseLegacyFlag;
- }
- void YGNode::setAndPropogateUseLegacyFlag(bool useLegacyFlag) {
- config_->useLegacyStretchBehaviour = useLegacyFlag;
- for_each(children_.begin(), children_.end(), [=](YGNodeRef childNode) {
- childNode->getConfig()->useLegacyStretchBehaviour = useLegacyFlag;
- });
- }
- void YGNode::setLayoutDoesLegacyFlagAffectsLayout(
- bool doesLegacyFlagAffectsLayout) {
- layout_.doesLegacyStretchFlagAffectsLayout = doesLegacyFlagAffectsLayout;
- }
- void YGNode::setLayoutDidUseLegacyFlag(bool didUseLegacyFlag) {
- layout_.didUseLegacyFlag = didUseLegacyFlag;
- }
- bool YGNode::isLayoutTreeEqualToNode(const YGNode& node) const {
- if (children_.size() != node.children_.size()) {
- return false;
- }
- if (layout_ != node.layout_) {
- return false;
- }
- if (children_.size() == 0) {
- return true;
- }
- bool isLayoutTreeEqual = true;
- YGNodeRef otherNodeChildren = nullptr;
- for (std::vector<YGNodeRef>::size_type i = 0; i < children_.size(); ++i) {
- otherNodeChildren = node.children_[i];
- isLayoutTreeEqual =
- children_[i]->isLayoutTreeEqualToNode(*otherNodeChildren);
- if (!isLayoutTreeEqual) {
- return false;
- }
- }
- return isLayoutTreeEqual;
- }
- 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");
- clearChildren();
- auto config = getConfig();
- *this = YGNode{};
- if (config->useWebDefaults) {
- setStyleFlexDirection(YGFlexDirectionRow);
- setStyleAlignContent(YGAlignStretch);
- }
- setConfig(config);
- }
|