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_(std::array<YGValue, 2>{YGValueUndefined, YGValueUndefined}) {}
409 * In the original file, to initialize resolvedDimensions_ above, we usee { { YGValueUndefined, YGValueUndefined } }.
410 * But it is not well work, so we modified it.
413 YGNode::YGNode(const YGNode& node)
414 : context_(node.context_),
416 hasNewLayout_(node.hasNewLayout_),
417 nodeType_(node.nodeType_),
418 measure_(node.measure_),
419 baseline_(node.baseline_),
420 dirtied_(node.dirtied_),
422 layout_(node.layout_),
423 lineIndex_(node.lineIndex_),
425 children_(node.children_),
426 nextChild_(node.nextChild_),
427 config_(node.config_),
428 isDirty_(node.isDirty_),
429 resolvedDimensions_(node.resolvedDimensions_) {}
431 YGNode::YGNode(const YGConfigRef newConfig) : YGNode() {
440 YGMeasureFunc measure,
441 YGBaselineFunc baseline,
442 YGDirtiedFunc dirtied,
443 const YGStyle& style,
444 const YGLayout& layout,
447 const YGVector& children,
451 std::array<YGValue, 2> resolvedDimensions)
454 hasNewLayout_(hasNewLayout),
461 lineIndex_(lineIndex),
464 nextChild_(nextChild),
467 resolvedDimensions_(resolvedDimensions) {}
469 YGNode& YGNode::operator=(const YGNode& node) {
474 for (auto child : children_) {
478 context_ = node.getContext();
479 print_ = node.getPrintFunc();
480 hasNewLayout_ = node.getHasNewLayout();
481 nodeType_ = node.getNodeType();
482 measure_ = node.getMeasure();
483 baseline_ = node.getBaseline();
484 dirtied_ = node.getDirtied();
485 style_ = node.style_;
486 layout_ = node.layout_;
487 lineIndex_ = node.getLineIndex();
488 owner_ = node.getOwner();
489 children_ = node.getChildren();
490 nextChild_ = node.getNextChild();
491 config_ = node.getConfig();
492 isDirty_ = node.isDirty();
493 resolvedDimensions_ = node.getResolvedDimensions();
498 YGValue YGNode::marginLeadingValue(const YGFlexDirection axis) const {
499 if (YGFlexDirectionIsRow(axis) &&
500 style_.margin[YGEdgeStart].unit != YGUnitUndefined) {
501 return style_.margin[YGEdgeStart];
503 return style_.margin[leading[axis]];
507 YGValue YGNode::marginTrailingValue(const YGFlexDirection axis) const {
508 if (YGFlexDirectionIsRow(axis) &&
509 style_.margin[YGEdgeEnd].unit != YGUnitUndefined) {
510 return style_.margin[YGEdgeEnd];
512 return style_.margin[trailing[axis]];
516 YGValue YGNode::resolveFlexBasisPtr() const {
517 YGValue flexBasis = style_.flexBasis;
518 if (flexBasis.unit != YGUnitAuto && flexBasis.unit != YGUnitUndefined) {
521 if (!style_.flex.isUndefined() && style_.flex.getValue() > 0.0f) {
522 return config_->useWebDefaults ? YGValueAuto : YGValueZero;
527 void YGNode::resolveDimension() {
528 for (uint32_t dim = YGDimensionWidth; dim < YGDimensionCount; dim++) {
529 if (getStyle().maxDimensions[dim].unit != YGUnitUndefined &&
531 getStyle().maxDimensions[dim], style_.minDimensions[dim])) {
532 resolvedDimensions_[dim] = style_.maxDimensions[dim];
534 resolvedDimensions_[dim] = style_.dimensions[dim];
539 YGDirection YGNode::resolveDirection(const YGDirection ownerDirection) {
540 if (style_.direction == YGDirectionInherit) {
541 return ownerDirection > YGDirectionInherit ? ownerDirection
544 return style_.direction;
548 void YGNode::clearChildren() {
550 children_.shrink_to_fit();
554 // All the member variables are deallocated externally, so no need to
560 void YGNode::cloneChildrenIfNeeded() {
561 // YGNodeRemoveChild in yoga.cpp has a forked variant of this algorithm
562 // optimized for deletions.
564 const uint32_t childCount = static_cast<uint32_t>(children_.size());
565 if (childCount == 0) {
566 // This is an empty set. Nothing to clone.
570 const YGNodeRef firstChild = children_.front();
571 if (firstChild->getOwner() == this) {
572 // If the first child has this node as its owner, we assume that it is
573 // already unique. We can do this because if we have it has a child, that
574 // means that its owner was at some point cloned which made that subtree
575 // immutable. We also assume that all its sibling are cloned as well.
579 const YGCloneNodeFunc cloneNodeCallback = config_->cloneNodeCallback;
580 for (uint32_t i = 0; i < childCount; ++i) {
581 const YGNodeRef oldChild = children_[i];
582 YGNodeRef newChild = nullptr;
583 if (cloneNodeCallback) {
584 newChild = cloneNodeCallback(oldChild, this, i);
586 if (newChild == nullptr) {
587 newChild = YGNodeClone(oldChild);
589 replaceChild(newChild, i);
590 newChild->setOwner(this);
594 void YGNode::markDirtyAndPropogate() {
597 setLayoutComputedFlexBasis(YGFloatOptional());
599 owner_->markDirtyAndPropogate();
604 void YGNode::markDirtyAndPropogateDownwards() {
606 for_each(children_.begin(), children_.end(), [](YGNodeRef childNode) {
607 childNode->markDirtyAndPropogateDownwards();
611 float YGNode::resolveFlexGrow() {
612 // Root nodes flexGrow should always be 0
613 if (owner_ == nullptr) {
616 if (!style_.flexGrow.isUndefined()) {
617 return style_.flexGrow.getValue();
619 if (!style_.flex.isUndefined() && style_.flex.getValue() > 0.0f) {
620 return style_.flex.getValue();
622 return kDefaultFlexGrow;
625 float YGNode::resolveFlexShrink() {
626 if (owner_ == nullptr) {
629 if (!style_.flexShrink.isUndefined()) {
630 return style_.flexShrink.getValue();
632 if (!config_->useWebDefaults && !style_.flex.isUndefined() &&
633 style_.flex.getValue() < 0.0f) {
634 return -style_.flex.getValue();
636 return config_->useWebDefaults ? kWebDefaultFlexShrink : kDefaultFlexShrink;
639 bool YGNode::isNodeFlexible() {
641 (style_.positionType == YGPositionTypeRelative) &&
642 (resolveFlexGrow() != 0 || resolveFlexShrink() != 0));
645 float YGNode::getLeadingBorder(const YGFlexDirection& axis) const {
646 if (YGFlexDirectionIsRow(axis) &&
647 style_.border[YGEdgeStart].unit != YGUnitUndefined &&
648 !YGFloatIsUndefined(style_.border[YGEdgeStart].value) &&
649 style_.border[YGEdgeStart].value >= 0.0f) {
650 return style_.border[YGEdgeStart].value;
653 float computedEdgeValue =
654 YGComputedEdgeValue(style_.border, leading[axis], &YGValueZero)->value;
655 return YGFloatMax(computedEdgeValue, 0.0f);
658 float YGNode::getTrailingBorder(const YGFlexDirection& flexDirection) const {
659 if (YGFlexDirectionIsRow(flexDirection) &&
660 style_.border[YGEdgeEnd].unit != YGUnitUndefined &&
661 !YGFloatIsUndefined(style_.border[YGEdgeEnd].value) &&
662 style_.border[YGEdgeEnd].value >= 0.0f) {
663 return style_.border[YGEdgeEnd].value;
666 float computedEdgeValue =
667 YGComputedEdgeValue(style_.border, trailing[flexDirection], &YGValueZero)
669 return YGFloatMax(computedEdgeValue, 0.0f);
672 YGFloatOptional YGNode::getLeadingPadding(
673 const YGFlexDirection& axis,
674 const float& widthSize) const {
675 const YGFloatOptional& paddingEdgeStart =
676 YGResolveValue(style_.padding[YGEdgeStart], widthSize);
677 if (YGFlexDirectionIsRow(axis) &&
678 style_.padding[YGEdgeStart].unit != YGUnitUndefined &&
679 !paddingEdgeStart.isUndefined() && paddingEdgeStart.getValue() > 0.0f) {
680 return paddingEdgeStart;
683 YGFloatOptional resolvedValue = YGResolveValue(
684 *YGComputedEdgeValue(style_.padding, leading[axis], &YGValueZero),
686 return YGFloatOptionalMax(resolvedValue, YGFloatOptional(0.0f));
689 YGFloatOptional YGNode::getTrailingPadding(
690 const YGFlexDirection& axis,
691 const float& widthSize) const {
692 if (YGFlexDirectionIsRow(axis) &&
693 style_.padding[YGEdgeEnd].unit != YGUnitUndefined &&
694 !YGResolveValue(style_.padding[YGEdgeEnd], widthSize).isUndefined() &&
695 YGResolveValue(style_.padding[YGEdgeEnd], widthSize).getValue() >= 0.0f) {
696 return YGResolveValue(style_.padding[YGEdgeEnd], widthSize);
699 YGFloatOptional resolvedValue = YGResolveValue(
700 *YGComputedEdgeValue(style_.padding, trailing[axis], &YGValueZero),
703 return YGFloatOptionalMax(resolvedValue, YGFloatOptional(0.0f));
706 YGFloatOptional YGNode::getLeadingPaddingAndBorder(
707 const YGFlexDirection& axis,
708 const float& widthSize) const {
709 return getLeadingPadding(axis, widthSize) +
710 YGFloatOptional(getLeadingBorder(axis));
713 YGFloatOptional YGNode::getTrailingPaddingAndBorder(
714 const YGFlexDirection& axis,
715 const float& widthSize) const {
716 return getTrailingPadding(axis, widthSize) +
717 YGFloatOptional(getTrailingBorder(axis));
720 bool YGNode::didUseLegacyFlag() {
721 bool didUseLegacyFlag = layout_.didUseLegacyFlag;
722 if (didUseLegacyFlag) {
725 for (const auto& child : children_) {
726 if (child->layout_.didUseLegacyFlag) {
727 didUseLegacyFlag = true;
731 return didUseLegacyFlag;
734 void YGNode::setAndPropogateUseLegacyFlag(bool useLegacyFlag) {
735 config_->useLegacyStretchBehaviour = useLegacyFlag;
736 for_each(children_.begin(), children_.end(), [=](YGNodeRef childNode) {
737 childNode->getConfig()->useLegacyStretchBehaviour = useLegacyFlag;
741 void YGNode::setLayoutDoesLegacyFlagAffectsLayout(
742 bool doesLegacyFlagAffectsLayout) {
743 layout_.doesLegacyStretchFlagAffectsLayout = doesLegacyFlagAffectsLayout;
746 void YGNode::setLayoutDidUseLegacyFlag(bool didUseLegacyFlag) {
747 layout_.didUseLegacyFlag = didUseLegacyFlag;
750 bool YGNode::isLayoutTreeEqualToNode(const YGNode& node) const {
751 if (children_.size() != node.children_.size()) {
754 if (layout_ != node.layout_) {
757 if (children_.size() == 0) {
761 bool isLayoutTreeEqual = true;
762 YGNodeRef otherNodeChildren = nullptr;
763 for (std::vector<YGNodeRef>::size_type i = 0; i < children_.size(); ++i) {
764 otherNodeChildren = node.children_[i];
766 children_[i]->isLayoutTreeEqualToNode(*otherNodeChildren);
767 if (!isLayoutTreeEqual) {
771 return isLayoutTreeEqual;