Rebase of facebook flexbox to yoga
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / third-party / yoga / YGNode.cpp
1 /**
2  * Copyright (c) 2014-present, Facebook, Inc.
3  *
4  * This source code is licensed under the MIT license found in the
5  * LICENSE file in the root directory of this source tree.
6  */
7
8 #include "YGNode.h"
9 #include <iostream>
10 #include "Utils.h"
11
12 void* YGNode::getContext() const {
13   return context_;
14 }
15
16 YGPrintFunc YGNode::getPrintFunc() const {
17   return print_;
18 }
19
20 bool YGNode::getHasNewLayout() const {
21   return hasNewLayout_;
22 }
23
24 YGNodeType YGNode::getNodeType() const {
25   return nodeType_;
26 }
27
28 YGMeasureFunc YGNode::getMeasure() const {
29   return measure_;
30 }
31
32 YGBaselineFunc YGNode::getBaseline() const {
33   return baseline_;
34 }
35
36 YGDirtiedFunc YGNode::getDirtied() const {
37   return dirtied_;
38 }
39
40 YGStyle& YGNode::getStyle() {
41   return style_;
42 }
43
44 YGLayout& YGNode::getLayout() {
45   return layout_;
46 }
47
48 uint32_t YGNode::getLineIndex() const {
49   return lineIndex_;
50 }
51
52 YGNodeRef YGNode::getOwner() const {
53   return owner_;
54 }
55
56 YGVector YGNode::getChildren() const {
57   return children_;
58 }
59
60 uint32_t YGNode::getChildrenCount() const {
61   return static_cast<uint32_t>(children_.size());
62 }
63
64 YGNodeRef YGNode::getChild(uint32_t index) const {
65   return children_.at(index);
66 }
67
68 YGNodeRef YGNode::getNextChild() const {
69   return nextChild_;
70 }
71
72 YGConfigRef YGNode::getConfig() const {
73   return config_;
74 }
75
76 bool YGNode::isDirty() const {
77   return isDirty_;
78 }
79
80 YGValue YGNode::getResolvedDimension(int index) {
81   return resolvedDimensions_[index];
82 }
83
84 std::array<YGValue, 2> YGNode::getResolvedDimensions() const {
85   return resolvedDimensions_;
86 }
87
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);
96     }
97   }
98
99   const YGValue* leadingPosition =
100       YGComputedEdgeValue(style_.position, leading[axis], &YGValueUndefined);
101
102   return leadingPosition->unit == YGUnitUndefined
103       ? YGFloatOptional(0)
104       : YGResolveValue(*leadingPosition, axisSize);
105 }
106
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);
115     }
116   }
117
118   const YGValue* trailingPosition =
119       YGComputedEdgeValue(style_.position, trailing[axis], &YGValueUndefined);
120
121   return trailingPosition->unit == YGUnitUndefined
122       ? YGFloatOptional(0)
123       : YGResolveValue(*trailingPosition, axisSize);
124 }
125
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;
132 }
133
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;
140 }
141
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);
148   }
149
150   return YGResolveValueMargin(
151       *YGComputedEdgeValue(style_.margin, leading[axis], &YGValueZero),
152       widthSize);
153 }
154
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);
161   }
162
163   return YGResolveValueMargin(
164       *YGComputedEdgeValue(style_.margin, trailing[axis], &YGValueZero),
165       widthSize);
166 }
167
168 YGFloatOptional YGNode::getMarginForAxis(
169     const YGFlexDirection& axis,
170     const float& widthSize) const {
171   return getLeadingMargin(axis, widthSize) + getTrailingMargin(axis, widthSize);
172 }
173
174 // Setters
175
176 void YGNode::setContext(void* context) {
177   context_ = context;
178 }
179
180 void YGNode::setPrintFunc(YGPrintFunc printFunc) {
181   print_ = printFunc;
182 }
183
184 void YGNode::setHasNewLayout(bool hasNewLayout) {
185   hasNewLayout_ = hasNewLayout;
186 }
187
188 void YGNode::setNodeType(YGNodeType nodeType) {
189   nodeType_ = nodeType;
190 }
191
192 void YGNode::setStyleFlexDirection(YGFlexDirection direction) {
193   style_.flexDirection = direction;
194 }
195
196 void YGNode::setStyleAlignContent(YGAlign alignContent) {
197   style_.alignContent = alignContent;
198 }
199
200 void YGNode::setMeasureFunc(YGMeasureFunc measureFunc) {
201   if (measureFunc == nullptr) {
202     measure_ = nullptr;
203     // TODO: t18095186 Move nodeType to opt-in function and mark appropriate
204     // places in Litho
205     nodeType_ = YGNodeTypeDefault;
206   } else {
207     YGAssertWithNode(
208         this,
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
213     // places in Litho
214     setNodeType(YGNodeTypeText);
215   }
216
217   measure_ = measureFunc;
218 }
219
220 void YGNode::setBaseLineFunc(YGBaselineFunc baseLineFunc) {
221   baseline_ = baseLineFunc;
222 }
223
224 void YGNode::setDirtiedFunc(YGDirtiedFunc dirtiedFunc) {
225   dirtied_ = dirtiedFunc;
226 }
227
228 void YGNode::setStyle(const YGStyle& style) {
229   style_ = style;
230 }
231
232 void YGNode::setLayout(const YGLayout& layout) {
233   layout_ = layout;
234 }
235
236 void YGNode::setLineIndex(uint32_t lineIndex) {
237   lineIndex_ = lineIndex;
238 }
239
240 void YGNode::setOwner(YGNodeRef owner) {
241   owner_ = owner;
242 }
243
244 void YGNode::setChildren(const YGVector& children) {
245   children_ = children;
246 }
247
248 void YGNode::setNextChild(YGNodeRef nextChild) {
249   nextChild_ = nextChild;
250 }
251
252 void YGNode::replaceChild(YGNodeRef child, uint32_t index) {
253   children_[index] = child;
254 }
255
256 void YGNode::replaceChild(YGNodeRef oldChild, YGNodeRef newChild) {
257   std::replace(children_.begin(), children_.end(), oldChild, newChild);
258 }
259
260 void YGNode::insertChild(YGNodeRef child, uint32_t index) {
261   children_.insert(children_.begin() + index, child);
262 }
263
264 void YGNode::setConfig(YGConfigRef config) {
265   config_ = config;
266 }
267
268 void YGNode::setDirty(bool isDirty) {
269   if (isDirty == isDirty_) {
270     return;
271   }
272   isDirty_ = isDirty;
273   if (isDirty && dirtied_) {
274     dirtied_(this);
275   }
276 }
277
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()) {
282     children_.erase(p);
283     return true;
284   }
285   return false;
286 }
287
288 void YGNode::removeChild(uint32_t index) {
289   children_.erase(children_.begin() + index);
290 }
291
292 void YGNode::setLayoutDirection(YGDirection direction) {
293   layout_.direction = direction;
294 }
295
296 void YGNode::setLayoutMargin(float margin, int index) {
297   layout_.margin[index] = margin;
298 }
299
300 void YGNode::setLayoutBorder(float border, int index) {
301   layout_.border[index] = border;
302 }
303
304 void YGNode::setLayoutPadding(float padding, int index) {
305   layout_.padding[index] = padding;
306 }
307
308 void YGNode::setLayoutLastOwnerDirection(YGDirection direction) {
309   layout_.lastOwnerDirection = direction;
310 }
311
312 void YGNode::setLayoutComputedFlexBasis(
313     const YGFloatOptional& computedFlexBasis) {
314   layout_.computedFlexBasis = computedFlexBasis;
315 }
316
317 void YGNode::setLayoutPosition(float position, int index) {
318   layout_.position[index] = position;
319 }
320
321 void YGNode::setLayoutComputedFlexBasisGeneration(
322     uint32_t computedFlexBasisGeneration) {
323   layout_.computedFlexBasisGeneration = computedFlexBasisGeneration;
324 }
325
326 void YGNode::setLayoutMeasuredDimension(float measuredDimension, int index) {
327   layout_.measuredDimensions[index] = measuredDimension;
328 }
329
330 void YGNode::setLayoutHadOverflow(bool hadOverflow) {
331   layout_.hadOverflow = hadOverflow;
332 }
333
334 void YGNode::setLayoutDimension(float dimension, int index) {
335   layout_.dimensions[index] = dimension;
336 }
337
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);
345   }
346
347   YGFloatOptional trailingPosition = getTrailingPosition(axis, axisSize);
348   if (!trailingPosition.isUndefined()) {
349     trailingPosition.setValue(-1 * trailingPosition.getValue());
350   }
351   return trailingPosition;
352 }
353
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
360    * values. */
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);
367
368   const YGFloatOptional relativePositionMain =
369       relativePosition(mainAxis, mainSize);
370   const YGFloatOptional relativePositionCross =
371       relativePosition(crossAxis, crossSize);
372
373   setLayoutPosition(
374       YGUnwrapFloatOptional(
375           getLeadingMargin(mainAxis, ownerWidth) + relativePositionMain),
376       leading[mainAxis]);
377   setLayoutPosition(
378       YGUnwrapFloatOptional(
379           getTrailingMargin(mainAxis, ownerWidth) + relativePositionMain),
380       trailing[mainAxis]);
381   setLayoutPosition(
382       YGUnwrapFloatOptional(
383           getLeadingMargin(crossAxis, ownerWidth) + relativePositionCross),
384       leading[crossAxis]);
385   setLayoutPosition(
386       YGUnwrapFloatOptional(
387           getTrailingMargin(crossAxis, ownerWidth) + relativePositionCross),
388       trailing[crossAxis]);
389 }
390
391 YGNode::YGNode()
392     : context_(nullptr),
393       print_(nullptr),
394       hasNewLayout_(true),
395       nodeType_(YGNodeTypeDefault),
396       measure_(nullptr),
397       baseline_(nullptr),
398       dirtied_(nullptr),
399       style_(YGStyle()),
400       layout_(YGLayout()),
401       lineIndex_(0),
402       owner_(nullptr),
403       children_(YGVector()),
404       nextChild_(nullptr),
405       config_(nullptr),
406       isDirty_(false),
407       resolvedDimensions_({{YGValueUndefined, YGValueUndefined}}) {}
408
409 YGNode::YGNode(const YGNode& node)
410     : context_(node.context_),
411       print_(node.print_),
412       hasNewLayout_(node.hasNewLayout_),
413       nodeType_(node.nodeType_),
414       measure_(node.measure_),
415       baseline_(node.baseline_),
416       dirtied_(node.dirtied_),
417       style_(node.style_),
418       layout_(node.layout_),
419       lineIndex_(node.lineIndex_),
420       owner_(node.owner_),
421       children_(node.children_),
422       nextChild_(node.nextChild_),
423       config_(node.config_),
424       isDirty_(node.isDirty_),
425       resolvedDimensions_(node.resolvedDimensions_) {}
426
427 YGNode::YGNode(const YGConfigRef newConfig) : YGNode() {
428   config_ = newConfig;
429 }
430
431 YGNode::YGNode(
432     void* context,
433     YGPrintFunc print,
434     bool hasNewLayout,
435     YGNodeType nodeType,
436     YGMeasureFunc measure,
437     YGBaselineFunc baseline,
438     YGDirtiedFunc dirtied,
439     YGStyle style,
440     const YGLayout& layout,
441     uint32_t lineIndex,
442     YGNodeRef owner,
443     const YGVector& children,
444     YGNodeRef nextChild,
445     YGConfigRef config,
446     bool isDirty,
447     std::array<YGValue, 2> resolvedDimensions)
448     : context_(context),
449       print_(print),
450       hasNewLayout_(hasNewLayout),
451       nodeType_(nodeType),
452       measure_(measure),
453       baseline_(baseline),
454       dirtied_(dirtied),
455       style_(style),
456       layout_(layout),
457       lineIndex_(lineIndex),
458       owner_(owner),
459       children_(children),
460       nextChild_(nextChild),
461       config_(config),
462       isDirty_(isDirty),
463       resolvedDimensions_(resolvedDimensions) {}
464
465 YGNode& YGNode::operator=(const YGNode& node) {
466   if (&node == this) {
467     return *this;
468   }
469
470   for (auto child : children_) {
471     delete child;
472   }
473
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();
490
491   return *this;
492 }
493
494 YGValue YGNode::marginLeadingValue(const YGFlexDirection axis) const {
495   if (YGFlexDirectionIsRow(axis) &&
496       style_.margin[YGEdgeStart].unit != YGUnitUndefined) {
497     return style_.margin[YGEdgeStart];
498   } else {
499     return style_.margin[leading[axis]];
500   }
501 }
502
503 YGValue YGNode::marginTrailingValue(const YGFlexDirection axis) const {
504   if (YGFlexDirectionIsRow(axis) &&
505       style_.margin[YGEdgeEnd].unit != YGUnitUndefined) {
506     return style_.margin[YGEdgeEnd];
507   } else {
508     return style_.margin[trailing[axis]];
509   }
510 }
511
512 YGValue YGNode::resolveFlexBasisPtr() const {
513   YGValue flexBasis = style_.flexBasis;
514   if (flexBasis.unit != YGUnitAuto && flexBasis.unit != YGUnitUndefined) {
515     return flexBasis;
516   }
517   if (!style_.flex.isUndefined() && style_.flex.getValue() > 0.0f) {
518     return config_->useWebDefaults ? YGValueAuto : YGValueZero;
519   }
520   return YGValueAuto;
521 }
522
523 void YGNode::resolveDimension() {
524   for (uint32_t dim = YGDimensionWidth; dim < YGDimensionCount; dim++) {
525     if (getStyle().maxDimensions[dim].unit != YGUnitUndefined &&
526         YGValueEqual(
527             getStyle().maxDimensions[dim], style_.minDimensions[dim])) {
528       resolvedDimensions_[dim] = style_.maxDimensions[dim];
529     } else {
530       resolvedDimensions_[dim] = style_.dimensions[dim];
531     }
532   }
533 }
534
535 YGDirection YGNode::resolveDirection(const YGDirection ownerDirection) {
536   if (style_.direction == YGDirectionInherit) {
537     return ownerDirection > YGDirectionInherit ? ownerDirection
538                                                 : YGDirectionLTR;
539   } else {
540     return style_.direction;
541   }
542 }
543
544 void YGNode::clearChildren() {
545   children_.clear();
546   children_.shrink_to_fit();
547 }
548
549 YGNode::~YGNode() {
550   // All the member variables are deallocated externally, so no need to
551   // deallocate here
552 }
553
554 // Other Methods
555
556 void YGNode::cloneChildrenIfNeeded() {
557   // YGNodeRemoveChild in yoga.cpp has a forked variant of this algorithm
558   // optimized for deletions.
559
560   const uint32_t childCount = static_cast<uint32_t>(children_.size());
561   if (childCount == 0) {
562     // This is an empty set. Nothing to clone.
563     return;
564   }
565
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.
572     return;
573   }
574
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);
581     }
582     if (newChild == nullptr) {
583       newChild = YGNodeClone(oldChild);
584     }
585     replaceChild(newChild, i);
586     newChild->setOwner(this);
587   }
588 }
589
590 void YGNode::markDirtyAndPropogate() {
591   if (!isDirty_) {
592     setDirty(true);
593     setLayoutComputedFlexBasis(YGFloatOptional());
594     if (owner_) {
595       owner_->markDirtyAndPropogate();
596     }
597   }
598 }
599
600 void YGNode::markDirtyAndPropogateDownwards() {
601   isDirty_ = true;
602   for_each(children_.begin(), children_.end(), [](YGNodeRef childNode) {
603     childNode->markDirtyAndPropogateDownwards();
604   });
605 }
606
607 float YGNode::resolveFlexGrow() {
608   // Root nodes flexGrow should always be 0
609   if (owner_ == nullptr) {
610     return 0.0;
611   }
612   if (!style_.flexGrow.isUndefined()) {
613     return style_.flexGrow.getValue();
614   }
615   if (!style_.flex.isUndefined() && style_.flex.getValue() > 0.0f) {
616     return style_.flex.getValue();
617   }
618   return kDefaultFlexGrow;
619 }
620
621 float YGNode::resolveFlexShrink() {
622   if (owner_ == nullptr) {
623     return 0.0;
624   }
625   if (!style_.flexShrink.isUndefined()) {
626     return style_.flexShrink.getValue();
627   }
628   if (!config_->useWebDefaults && !style_.flex.isUndefined() &&
629       style_.flex.getValue() < 0.0f) {
630     return -style_.flex.getValue();
631   }
632   return config_->useWebDefaults ? kWebDefaultFlexShrink : kDefaultFlexShrink;
633 }
634
635 bool YGNode::isNodeFlexible() {
636   return (
637       (style_.positionType == YGPositionTypeRelative) &&
638       (resolveFlexGrow() != 0 || resolveFlexShrink() != 0));
639 }
640
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;
647   }
648
649   float computedEdgeValue =
650       YGComputedEdgeValue(style_.border, leading[axis], &YGValueZero)->value;
651   return YGFloatMax(computedEdgeValue, 0.0f);
652 }
653
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;
660   }
661
662   float computedEdgeValue =
663       YGComputedEdgeValue(style_.border, trailing[flexDirection], &YGValueZero)
664           ->value;
665   return YGFloatMax(computedEdgeValue, 0.0f);
666 }
667
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;
677   }
678
679   YGFloatOptional resolvedValue = YGResolveValue(
680       *YGComputedEdgeValue(style_.padding, leading[axis], &YGValueZero),
681       widthSize);
682   return YGFloatOptionalMax(resolvedValue, YGFloatOptional(0.0f));
683 }
684
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);
693   }
694
695   YGFloatOptional resolvedValue = YGResolveValue(
696       *YGComputedEdgeValue(style_.padding, trailing[axis], &YGValueZero),
697       widthSize);
698
699   return YGFloatOptionalMax(resolvedValue, YGFloatOptional(0.0f));
700 }
701
702 YGFloatOptional YGNode::getLeadingPaddingAndBorder(
703     const YGFlexDirection& axis,
704     const float& widthSize) const {
705   return getLeadingPadding(axis, widthSize) +
706       YGFloatOptional(getLeadingBorder(axis));
707 }
708
709 YGFloatOptional YGNode::getTrailingPaddingAndBorder(
710     const YGFlexDirection& axis,
711     const float& widthSize) const {
712   return getTrailingPadding(axis, widthSize) +
713       YGFloatOptional(getTrailingBorder(axis));
714 }
715
716 bool YGNode::didUseLegacyFlag() {
717   bool didUseLegacyFlag = layout_.didUseLegacyFlag;
718   if (didUseLegacyFlag) {
719     return true;
720   }
721   for (const auto& child : children_) {
722     if (child->layout_.didUseLegacyFlag) {
723       didUseLegacyFlag = true;
724       break;
725     }
726   }
727   return didUseLegacyFlag;
728 }
729
730 void YGNode::setAndPropogateUseLegacyFlag(bool useLegacyFlag) {
731   config_->useLegacyStretchBehaviour = useLegacyFlag;
732   for_each(children_.begin(), children_.end(), [=](YGNodeRef childNode) {
733     childNode->getConfig()->useLegacyStretchBehaviour = useLegacyFlag;
734   });
735 }
736
737 void YGNode::setLayoutDoesLegacyFlagAffectsLayout(
738     bool doesLegacyFlagAffectsLayout) {
739   layout_.doesLegacyStretchFlagAffectsLayout = doesLegacyFlagAffectsLayout;
740 }
741
742 void YGNode::setLayoutDidUseLegacyFlag(bool didUseLegacyFlag) {
743   layout_.didUseLegacyFlag = didUseLegacyFlag;
744 }
745
746 bool YGNode::isLayoutTreeEqualToNode(const YGNode& node) const {
747   if (children_.size() != node.children_.size()) {
748     return false;
749   }
750   if (layout_ != node.layout_) {
751     return false;
752   }
753   if (children_.size() == 0) {
754     return true;
755   }
756
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];
761     isLayoutTreeEqual =
762         children_[i]->isLayoutTreeEqualToNode(*otherNodeChildren);
763     if (!isLayoutTreeEqual) {
764       return false;
765     }
766   }
767   return isLayoutTreeEqual;
768 }