2 * Copyright (c) 2014-present, Facebook, Inc.
4 * This source code is licensed under the MIT license found in the
5 * LICENSE file in the root directory of this source tree.
12 void* YGNode::getContext() const {
16 YGPrintFunc YGNode::getPrintFunc() const {
20 bool YGNode::getHasNewLayout() const {
24 YGNodeType YGNode::getNodeType() const {
28 YGMeasureFunc YGNode::getMeasure() const {
32 YGBaselineFunc YGNode::getBaseline() const {
36 YGDirtiedFunc YGNode::getDirtied() const {
40 YGStyle& YGNode::getStyle() {
44 YGLayout& YGNode::getLayout() {
48 uint32_t YGNode::getLineIndex() const {
52 YGNodeRef YGNode::getOwner() const {
56 YGVector YGNode::getChildren() const {
60 uint32_t YGNode::getChildrenCount() const {
61 return static_cast<uint32_t>(children_.size());
64 YGNodeRef YGNode::getChild(uint32_t index) const {
65 return children_.at(index);
68 YGNodeRef YGNode::getNextChild() const {
72 YGConfigRef YGNode::getConfig() const {
76 bool YGNode::isDirty() const {
80 YGValue YGNode::getResolvedDimension(int index) {
81 return resolvedDimensions_[index];
84 std::array<YGValue, 2> YGNode::getResolvedDimensions() const {
85 return resolvedDimensions_;
88 YGFloatOptional YGNode::getLeadingPosition(
89 const YGFlexDirection& axis,
90 const float& axisSize) const {
91 if (YGFlexDirectionIsRow(axis)) {
92 const YGValue* leadingPosition =
93 YGComputedEdgeValue(style_.position, YGEdgeStart, &YGValueUndefined);
94 if (leadingPosition->unit != YGUnitUndefined) {
95 return YGResolveValue(*leadingPosition, axisSize);
99 const YGValue* leadingPosition =
100 YGComputedEdgeValue(style_.position, leading[axis], &YGValueUndefined);
102 return leadingPosition->unit == YGUnitUndefined
104 : YGResolveValue(*leadingPosition, axisSize);
107 YGFloatOptional YGNode::getTrailingPosition(
108 const YGFlexDirection& axis,
109 const float& axisSize) const {
110 if (YGFlexDirectionIsRow(axis)) {
111 const YGValue* trailingPosition =
112 YGComputedEdgeValue(style_.position, YGEdgeEnd, &YGValueUndefined);
113 if (trailingPosition->unit != YGUnitUndefined) {
114 return YGResolveValue(*trailingPosition, axisSize);
118 const YGValue* trailingPosition =
119 YGComputedEdgeValue(style_.position, trailing[axis], &YGValueUndefined);
121 return trailingPosition->unit == YGUnitUndefined
123 : YGResolveValue(*trailingPosition, axisSize);
126 bool YGNode::isLeadingPositionDefined(const YGFlexDirection& axis) const {
127 return (YGFlexDirectionIsRow(axis) &&
128 YGComputedEdgeValue(style_.position, YGEdgeStart, &YGValueUndefined)
129 ->unit != YGUnitUndefined) ||
130 YGComputedEdgeValue(style_.position, leading[axis], &YGValueUndefined)
131 ->unit != YGUnitUndefined;
134 bool YGNode::isTrailingPosDefined(const YGFlexDirection& axis) const {
135 return (YGFlexDirectionIsRow(axis) &&
136 YGComputedEdgeValue(style_.position, YGEdgeEnd, &YGValueUndefined)
137 ->unit != YGUnitUndefined) ||
138 YGComputedEdgeValue(style_.position, trailing[axis], &YGValueUndefined)
139 ->unit != YGUnitUndefined;
142 YGFloatOptional YGNode::getLeadingMargin(
143 const YGFlexDirection& axis,
144 const float& widthSize) const {
145 if (YGFlexDirectionIsRow(axis) &&
146 style_.margin[YGEdgeStart].unit != YGUnitUndefined) {
147 return YGResolveValueMargin(style_.margin[YGEdgeStart], widthSize);
150 return YGResolveValueMargin(
151 *YGComputedEdgeValue(style_.margin, leading[axis], &YGValueZero),
155 YGFloatOptional YGNode::getTrailingMargin(
156 const YGFlexDirection& axis,
157 const float& widthSize) const {
158 if (YGFlexDirectionIsRow(axis) &&
159 style_.margin[YGEdgeEnd].unit != YGUnitUndefined) {
160 return YGResolveValueMargin(style_.margin[YGEdgeEnd], widthSize);
163 return YGResolveValueMargin(
164 *YGComputedEdgeValue(style_.margin, trailing[axis], &YGValueZero),
168 YGFloatOptional YGNode::getMarginForAxis(
169 const YGFlexDirection& axis,
170 const float& widthSize) const {
171 return getLeadingMargin(axis, widthSize) + getTrailingMargin(axis, widthSize);
176 void YGNode::setContext(void* context) {
180 void YGNode::setPrintFunc(YGPrintFunc printFunc) {
184 void YGNode::setHasNewLayout(bool hasNewLayout) {
185 hasNewLayout_ = hasNewLayout;
188 void YGNode::setNodeType(YGNodeType nodeType) {
189 nodeType_ = nodeType;
192 void YGNode::setStyleFlexDirection(YGFlexDirection direction) {
193 style_.flexDirection = direction;
196 void YGNode::setStyleAlignContent(YGAlign alignContent) {
197 style_.alignContent = alignContent;
200 void YGNode::setMeasureFunc(YGMeasureFunc measureFunc) {
201 if (measureFunc == nullptr) {
203 // TODO: t18095186 Move nodeType to opt-in function and mark appropriate
205 nodeType_ = YGNodeTypeDefault;
209 children_.size() == 0,
210 "Cannot set measure function: Nodes with measure functions cannot have children.");
211 measure_ = measureFunc;
212 // TODO: t18095186 Move nodeType to opt-in function and mark appropriate
214 setNodeType(YGNodeTypeText);
217 measure_ = measureFunc;
220 void YGNode::setBaseLineFunc(YGBaselineFunc baseLineFunc) {
221 baseline_ = baseLineFunc;
224 void YGNode::setDirtiedFunc(YGDirtiedFunc dirtiedFunc) {
225 dirtied_ = dirtiedFunc;
228 void YGNode::setStyle(const YGStyle& style) {
232 void YGNode::setLayout(const YGLayout& layout) {
236 void YGNode::setLineIndex(uint32_t lineIndex) {
237 lineIndex_ = lineIndex;
240 void YGNode::setOwner(YGNodeRef owner) {
244 void YGNode::setChildren(const YGVector& children) {
245 children_ = children;
248 void YGNode::setNextChild(YGNodeRef nextChild) {
249 nextChild_ = nextChild;
252 void YGNode::replaceChild(YGNodeRef child, uint32_t index) {
253 children_[index] = child;
256 void YGNode::replaceChild(YGNodeRef oldChild, YGNodeRef newChild) {
257 std::replace(children_.begin(), children_.end(), oldChild, newChild);
260 void YGNode::insertChild(YGNodeRef child, uint32_t index) {
261 children_.insert(children_.begin() + index, child);
264 void YGNode::setConfig(YGConfigRef config) {
268 void YGNode::setDirty(bool isDirty) {
269 if (isDirty == isDirty_) {
273 if (isDirty && dirtied_) {
278 bool YGNode::removeChild(YGNodeRef child) {
279 std::vector<YGNodeRef>::iterator p =
280 std::find(children_.begin(), children_.end(), child);
281 if (p != children_.end()) {
288 void YGNode::removeChild(uint32_t index) {
289 children_.erase(children_.begin() + index);
292 void YGNode::setLayoutDirection(YGDirection direction) {
293 layout_.direction = direction;
296 void YGNode::setLayoutMargin(float margin, int index) {
297 layout_.margin[index] = margin;
300 void YGNode::setLayoutBorder(float border, int index) {
301 layout_.border[index] = border;
304 void YGNode::setLayoutPadding(float padding, int index) {
305 layout_.padding[index] = padding;
308 void YGNode::setLayoutLastOwnerDirection(YGDirection direction) {
309 layout_.lastOwnerDirection = direction;
312 void YGNode::setLayoutComputedFlexBasis(
313 const YGFloatOptional& computedFlexBasis) {
314 layout_.computedFlexBasis = computedFlexBasis;
317 void YGNode::setLayoutPosition(float position, int index) {
318 layout_.position[index] = position;
321 void YGNode::setLayoutComputedFlexBasisGeneration(
322 uint32_t computedFlexBasisGeneration) {
323 layout_.computedFlexBasisGeneration = computedFlexBasisGeneration;
326 void YGNode::setLayoutMeasuredDimension(float measuredDimension, int index) {
327 layout_.measuredDimensions[index] = measuredDimension;
330 void YGNode::setLayoutHadOverflow(bool hadOverflow) {
331 layout_.hadOverflow = hadOverflow;
334 void YGNode::setLayoutDimension(float dimension, int index) {
335 layout_.dimensions[index] = dimension;
338 // If both left and right are defined, then use left. Otherwise return
339 // +left or -right depending on which is defined.
340 YGFloatOptional YGNode::relativePosition(
341 const YGFlexDirection& axis,
342 const float& axisSize) const {
343 if (isLeadingPositionDefined(axis)) {
344 return getLeadingPosition(axis, axisSize);
347 YGFloatOptional trailingPosition = getTrailingPosition(axis, axisSize);
348 if (!trailingPosition.isUndefined()) {
349 trailingPosition.setValue(-1 * trailingPosition.getValue());
351 return trailingPosition;
354 void YGNode::setPosition(
355 const YGDirection direction,
356 const float mainSize,
357 const float crossSize,
358 const float ownerWidth) {
359 /* Root nodes should be always layouted as LTR, so we don't return negative
361 const YGDirection directionRespectingRoot =
362 owner_ != nullptr ? direction : YGDirectionLTR;
363 const YGFlexDirection mainAxis =
364 YGResolveFlexDirection(style_.flexDirection, directionRespectingRoot);
365 const YGFlexDirection crossAxis =
366 YGFlexDirectionCross(mainAxis, directionRespectingRoot);
368 const YGFloatOptional relativePositionMain =
369 relativePosition(mainAxis, mainSize);
370 const YGFloatOptional relativePositionCross =
371 relativePosition(crossAxis, crossSize);
374 YGUnwrapFloatOptional(
375 getLeadingMargin(mainAxis, ownerWidth) + relativePositionMain),
378 YGUnwrapFloatOptional(
379 getTrailingMargin(mainAxis, ownerWidth) + relativePositionMain),
382 YGUnwrapFloatOptional(
383 getLeadingMargin(crossAxis, ownerWidth) + relativePositionCross),
386 YGUnwrapFloatOptional(
387 getTrailingMargin(crossAxis, ownerWidth) + relativePositionCross),
388 trailing[crossAxis]);
395 nodeType_(YGNodeTypeDefault),
403 children_(YGVector()),
407 resolvedDimensions_({{YGValueUndefined, YGValueUndefined}}) {}
409 YGNode::YGNode(const YGNode& node)
410 : context_(node.context_),
412 hasNewLayout_(node.hasNewLayout_),
413 nodeType_(node.nodeType_),
414 measure_(node.measure_),
415 baseline_(node.baseline_),
416 dirtied_(node.dirtied_),
418 layout_(node.layout_),
419 lineIndex_(node.lineIndex_),
421 children_(node.children_),
422 nextChild_(node.nextChild_),
423 config_(node.config_),
424 isDirty_(node.isDirty_),
425 resolvedDimensions_(node.resolvedDimensions_) {}
427 YGNode::YGNode(const YGConfigRef newConfig) : YGNode() {
436 YGMeasureFunc measure,
437 YGBaselineFunc baseline,
438 YGDirtiedFunc dirtied,
439 const YGStyle& style,
440 const YGLayout& layout,
443 const YGVector& children,
447 std::array<YGValue, 2> resolvedDimensions)
450 hasNewLayout_(hasNewLayout),
457 lineIndex_(lineIndex),
460 nextChild_(nextChild),
463 resolvedDimensions_(resolvedDimensions) {}
465 YGNode& YGNode::operator=(const YGNode& node) {
470 for (auto child : children_) {
474 context_ = node.getContext();
475 print_ = node.getPrintFunc();
476 hasNewLayout_ = node.getHasNewLayout();
477 nodeType_ = node.getNodeType();
478 measure_ = node.getMeasure();
479 baseline_ = node.getBaseline();
480 dirtied_ = node.getDirtied();
481 style_ = node.style_;
482 layout_ = node.layout_;
483 lineIndex_ = node.getLineIndex();
484 owner_ = node.getOwner();
485 children_ = node.getChildren();
486 nextChild_ = node.getNextChild();
487 config_ = node.getConfig();
488 isDirty_ = node.isDirty();
489 resolvedDimensions_ = node.getResolvedDimensions();
494 YGValue YGNode::marginLeadingValue(const YGFlexDirection axis) const {
495 if (YGFlexDirectionIsRow(axis) &&
496 style_.margin[YGEdgeStart].unit != YGUnitUndefined) {
497 return style_.margin[YGEdgeStart];
499 return style_.margin[leading[axis]];
503 YGValue YGNode::marginTrailingValue(const YGFlexDirection axis) const {
504 if (YGFlexDirectionIsRow(axis) &&
505 style_.margin[YGEdgeEnd].unit != YGUnitUndefined) {
506 return style_.margin[YGEdgeEnd];
508 return style_.margin[trailing[axis]];
512 YGValue YGNode::resolveFlexBasisPtr() const {
513 YGValue flexBasis = style_.flexBasis;
514 if (flexBasis.unit != YGUnitAuto && flexBasis.unit != YGUnitUndefined) {
517 if (!style_.flex.isUndefined() && style_.flex.getValue() > 0.0f) {
518 return config_->useWebDefaults ? YGValueAuto : YGValueZero;
523 void YGNode::resolveDimension() {
524 for (uint32_t dim = YGDimensionWidth; dim < YGDimensionCount; dim++) {
525 if (getStyle().maxDimensions[dim].unit != YGUnitUndefined &&
527 getStyle().maxDimensions[dim], style_.minDimensions[dim])) {
528 resolvedDimensions_[dim] = style_.maxDimensions[dim];
530 resolvedDimensions_[dim] = style_.dimensions[dim];
535 YGDirection YGNode::resolveDirection(const YGDirection ownerDirection) {
536 if (style_.direction == YGDirectionInherit) {
537 return ownerDirection > YGDirectionInherit ? ownerDirection
540 return style_.direction;
544 void YGNode::clearChildren() {
546 children_.shrink_to_fit();
550 // All the member variables are deallocated externally, so no need to
556 void YGNode::cloneChildrenIfNeeded() {
557 // YGNodeRemoveChild in yoga.cpp has a forked variant of this algorithm
558 // optimized for deletions.
560 const uint32_t childCount = static_cast<uint32_t>(children_.size());
561 if (childCount == 0) {
562 // This is an empty set. Nothing to clone.
566 const YGNodeRef firstChild = children_.front();
567 if (firstChild->getOwner() == this) {
568 // If the first child has this node as its owner, we assume that it is
569 // already unique. We can do this because if we have it has a child, that
570 // means that its owner was at some point cloned which made that subtree
571 // immutable. We also assume that all its sibling are cloned as well.
575 const YGCloneNodeFunc cloneNodeCallback = config_->cloneNodeCallback;
576 for (uint32_t i = 0; i < childCount; ++i) {
577 const YGNodeRef oldChild = children_[i];
578 YGNodeRef newChild = nullptr;
579 if (cloneNodeCallback) {
580 newChild = cloneNodeCallback(oldChild, this, i);
582 if (newChild == nullptr) {
583 newChild = YGNodeClone(oldChild);
585 replaceChild(newChild, i);
586 newChild->setOwner(this);
590 void YGNode::markDirtyAndPropogate() {
593 setLayoutComputedFlexBasis(YGFloatOptional());
595 owner_->markDirtyAndPropogate();
600 void YGNode::markDirtyAndPropogateDownwards() {
602 for_each(children_.begin(), children_.end(), [](YGNodeRef childNode) {
603 childNode->markDirtyAndPropogateDownwards();
607 float YGNode::resolveFlexGrow() {
608 // Root nodes flexGrow should always be 0
609 if (owner_ == nullptr) {
612 if (!style_.flexGrow.isUndefined()) {
613 return style_.flexGrow.getValue();
615 if (!style_.flex.isUndefined() && style_.flex.getValue() > 0.0f) {
616 return style_.flex.getValue();
618 return kDefaultFlexGrow;
621 float YGNode::resolveFlexShrink() {
622 if (owner_ == nullptr) {
625 if (!style_.flexShrink.isUndefined()) {
626 return style_.flexShrink.getValue();
628 if (!config_->useWebDefaults && !style_.flex.isUndefined() &&
629 style_.flex.getValue() < 0.0f) {
630 return -style_.flex.getValue();
632 return config_->useWebDefaults ? kWebDefaultFlexShrink : kDefaultFlexShrink;
635 bool YGNode::isNodeFlexible() {
637 (style_.positionType == YGPositionTypeRelative) &&
638 (resolveFlexGrow() != 0 || resolveFlexShrink() != 0));
641 float YGNode::getLeadingBorder(const YGFlexDirection& axis) const {
642 if (YGFlexDirectionIsRow(axis) &&
643 style_.border[YGEdgeStart].unit != YGUnitUndefined &&
644 !YGFloatIsUndefined(style_.border[YGEdgeStart].value) &&
645 style_.border[YGEdgeStart].value >= 0.0f) {
646 return style_.border[YGEdgeStart].value;
649 float computedEdgeValue =
650 YGComputedEdgeValue(style_.border, leading[axis], &YGValueZero)->value;
651 return YGFloatMax(computedEdgeValue, 0.0f);
654 float YGNode::getTrailingBorder(const YGFlexDirection& flexDirection) const {
655 if (YGFlexDirectionIsRow(flexDirection) &&
656 style_.border[YGEdgeEnd].unit != YGUnitUndefined &&
657 !YGFloatIsUndefined(style_.border[YGEdgeEnd].value) &&
658 style_.border[YGEdgeEnd].value >= 0.0f) {
659 return style_.border[YGEdgeEnd].value;
662 float computedEdgeValue =
663 YGComputedEdgeValue(style_.border, trailing[flexDirection], &YGValueZero)
665 return YGFloatMax(computedEdgeValue, 0.0f);
668 YGFloatOptional YGNode::getLeadingPadding(
669 const YGFlexDirection& axis,
670 const float& widthSize) const {
671 const YGFloatOptional& paddingEdgeStart =
672 YGResolveValue(style_.padding[YGEdgeStart], widthSize);
673 if (YGFlexDirectionIsRow(axis) &&
674 style_.padding[YGEdgeStart].unit != YGUnitUndefined &&
675 !paddingEdgeStart.isUndefined() && paddingEdgeStart.getValue() > 0.0f) {
676 return paddingEdgeStart;
679 YGFloatOptional resolvedValue = YGResolveValue(
680 *YGComputedEdgeValue(style_.padding, leading[axis], &YGValueZero),
682 return YGFloatOptionalMax(resolvedValue, YGFloatOptional(0.0f));
685 YGFloatOptional YGNode::getTrailingPadding(
686 const YGFlexDirection& axis,
687 const float& widthSize) const {
688 if (YGFlexDirectionIsRow(axis) &&
689 style_.padding[YGEdgeEnd].unit != YGUnitUndefined &&
690 !YGResolveValue(style_.padding[YGEdgeEnd], widthSize).isUndefined() &&
691 YGResolveValue(style_.padding[YGEdgeEnd], widthSize).getValue() >= 0.0f) {
692 return YGResolveValue(style_.padding[YGEdgeEnd], widthSize);
695 YGFloatOptional resolvedValue = YGResolveValue(
696 *YGComputedEdgeValue(style_.padding, trailing[axis], &YGValueZero),
699 return YGFloatOptionalMax(resolvedValue, YGFloatOptional(0.0f));
702 YGFloatOptional YGNode::getLeadingPaddingAndBorder(
703 const YGFlexDirection& axis,
704 const float& widthSize) const {
705 return getLeadingPadding(axis, widthSize) +
706 YGFloatOptional(getLeadingBorder(axis));
709 YGFloatOptional YGNode::getTrailingPaddingAndBorder(
710 const YGFlexDirection& axis,
711 const float& widthSize) const {
712 return getTrailingPadding(axis, widthSize) +
713 YGFloatOptional(getTrailingBorder(axis));
716 bool YGNode::didUseLegacyFlag() {
717 bool didUseLegacyFlag = layout_.didUseLegacyFlag;
718 if (didUseLegacyFlag) {
721 for (const auto& child : children_) {
722 if (child->layout_.didUseLegacyFlag) {
723 didUseLegacyFlag = true;
727 return didUseLegacyFlag;
730 void YGNode::setAndPropogateUseLegacyFlag(bool useLegacyFlag) {
731 config_->useLegacyStretchBehaviour = useLegacyFlag;
732 for_each(children_.begin(), children_.end(), [=](YGNodeRef childNode) {
733 childNode->getConfig()->useLegacyStretchBehaviour = useLegacyFlag;
737 void YGNode::setLayoutDoesLegacyFlagAffectsLayout(
738 bool doesLegacyFlagAffectsLayout) {
739 layout_.doesLegacyStretchFlagAffectsLayout = doesLegacyFlagAffectsLayout;
742 void YGNode::setLayoutDidUseLegacyFlag(bool didUseLegacyFlag) {
743 layout_.didUseLegacyFlag = didUseLegacyFlag;
746 bool YGNode::isLayoutTreeEqualToNode(const YGNode& node) const {
747 if (children_.size() != node.children_.size()) {
750 if (layout_ != node.layout_) {
753 if (children_.size() == 0) {
757 bool isLayoutTreeEqual = true;
758 YGNodeRef otherNodeChildren = nullptr;
759 for (std::vector<YGNodeRef>::size_type i = 0; i < children_.size(); ++i) {
760 otherNodeChildren = node.children_[i];
762 children_[i]->isLayoutTreeEqualToNode(*otherNodeChildren);
763 if (!isLayoutTreeEqual) {
767 return isLayoutTreeEqual;